Beispiel #1
0
        public double ReadFlonum(FaslFile file, uint offset)
        {
            //EncodedObject header = this [arg0Offset];
            byte b0 = ReadByte(offset + 4);
            byte b1 = ReadByte(offset + 5);
            byte b2 = ReadByte(offset + 6);
            byte b3 = ReadByte(offset + 7);
            byte b4 = ReadByte(offset + 8);
            byte b5 = ReadByte(offset + 9);
            byte b6 = ReadByte(offset + 10);
            byte b7 = ReadByte(offset + 11);

            if ((b0 == 0) &&
                (b1 == 0) &&
                (b2 == 0) &&
                (b3 == 0) &&
                (b4 == 0) &&
                (b5 == 0) &&
                (b6 == 0) &&
                (b7 == 0))
            {
                return(0.0);
            }
            int encodedExponent = (b7 & 0x7F) << 4;

            encodedExponent += (b6 & 0xF0) >> 4;
            long mantissa = (encodedExponent == 0) ? 0 : 1;

            mantissa *= 16;
            mantissa += b6 & 0x0F;
            mantissa *= 256;
            mantissa += b5;
            mantissa *= 256;
            mantissa += b4;
            mantissa *= 256;
            mantissa += b3;
            mantissa *= 256;
            mantissa += b2;
            mantissa *= 256;
            mantissa += b1;
            mantissa *= 256;
            mantissa += b0;
            int exponent = -(1024 + 51);

            exponent += encodedExponent;
            int    sign   = ((b7 & 0x80) == 0) ? 1 : -1;
            double answer = FloatArithmetic.EncodeFloat(sign, exponent, mantissa);

            return(answer);
        }
Beispiel #2
0
        public double ToDouble()
        {
            if (this.IsZero)
            {
                return(0.0);
            }

            {
                int         length      = this.Length;
                int         index       = length - 1;
                int         scale_words = length - 1;
                BignumDigit msd         = this [index];

                int bits_to_get = 53; //DBL_MANT_DIG; /* includes implicit 1 */

                double value                   = 0;
                long   mask                    = 0;
                long   guard_bit_mask          = BIGNUM_RADIX >> 1;
                long   rounding_correction     = 0;
                int    current_digit_bit_count = 0;
                long   w = msd.ToLong();
                current_digit_bit_count = 0;

                while (w > 0xff)
                {
                    current_digit_bit_count += 8;
                    w >>= 8;
                }

                while (w > 0)
                {
                    current_digit_bit_count += 1;
                    w >>= 1;
                }

                mask = (1 << (current_digit_bit_count)) - 1;

                while (true)
                {
                    if (current_digit_bit_count > bits_to_get)
                    {
                        guard_bit_mask          = (1 << (current_digit_bit_count - bits_to_get - 1));
                        mask                   &= ~((guard_bit_mask << 1) - 1);
                        current_digit_bit_count = bits_to_get;
                        bits_to_get             = 0;
                    }
                    else
                    {
                        bits_to_get -= current_digit_bit_count;
                    }

                    value = (value * BIGNUM_RADIX) + (this [index].ToLong() & mask);

                    if (bits_to_get == 0)
                    {
                        scale_words = index;
                        if (current_digit_bit_count == BIGNUM_DIGIT_LENGTH)
                        {
                            if (index == 0) /* there is no guard bit */
                            {
                                goto finished;
                            }
                            guard_bit_mask      = (1 << (BIGNUM_DIGIT_LENGTH - 1));
                            rounding_correction = 1;
                            index -= 1;
                        }
                        else
                        {
                            rounding_correction = (guard_bit_mask << 1);
                        }
                        break;
                    }
                    if (index == 0)  /* fewer than DBL_MANT_DIG bits */
                    {
                        goto finished;
                    }

                    index -= 1;
                    current_digit_bit_count = BIGNUM_DIGIT_LENGTH;
                    mask = BIGNUM_DIGIT_MASK;
                }

                /* round-to-even depending on lsb, guard and following bits: lgfffff */

                if ((this [index].ToLong() & guard_bit_mask) == 0)  /* case x0xxxx */
                {
                    goto round_down;
                }

                if ((this [index].ToLong() & (guard_bit_mask - 1)) != 0)  /* case x1xx1x */
                {
                    goto round_up;
                }

                /* cases 110000 and 1101xx: test "odd?", i.e. round-to-even rounds up */
                if ((guard_bit_mask << 1) == BIGNUM_RADIX)
                {
                    if ((this [index + 1].ToLong() & 1) != 0)   /* "odd?" */
                    {
                        goto round_up;
                    }
                }
                else
                {
                    if ((this [index].ToLong() & (guard_bit_mask << 1)) != 0)
                    {
                        goto round_up;
                    }
                }

                if (index == 0)   /* case 010000, no more words of following bits */
                {
                    goto finished;
                }

                { /* distinguish between cases 0100...00 and 0100..1xx, multiple words */
                    int index2 = index - 1;
                    while (index2 >= 0)
                    {
                        if (this [index] != 0)
                        {
                            goto round_up;
                        }
                        index2--;
                    }
                    goto round_down;
                }

round_up:
                value += rounding_correction;
round_down:

                /* note, ldexp `sticks' at the maximal non-infinity value, which
                 * is a reasonable compromise for numbers with DBL_MAX_EXP bits
                 * that round up */
                if (scale_words > 0)
                {
                    value = FloatArithmetic.LdExp(value, scale_words * BIGNUM_DIGIT_LENGTH);
                }

finished:
                return(this.IsNegative ? (-value) : value);
            }
        }