Пример #1
0
        BignumDigit DestructiveScaleDown(BignumDigit denominator)
        {
            BignumDigit numerator;
            BignumDigit remainder = (BignumDigit)0L;
            BignumDigit twoDigits;
            int         start = 0;
            int         scan  = start + this.Length;

            while (start < scan)
            {
                twoDigits   = this [--scan];
                numerator   = new BignumDigit(remainder.ToLong(), twoDigits.High);
                remainder   = (BignumDigit)(numerator.ToLong() / denominator.ToLong());
                numerator   = new BignumDigit(numerator.ToLong() % denominator.ToLong(), twoDigits.Low);
                this [scan] = new BignumDigit(remainder.ToLong(), numerator.ToLong() / denominator.ToLong());
                remainder   = (BignumDigit)(numerator.ToLong() % denominator.ToLong());
            }
            return(remainder);
        }
Пример #2
0
        BignumDigit DestructiveScaleDown (BignumDigit denominator)
        {
            BignumDigit numerator;
            BignumDigit remainder = (BignumDigit) 0L;
            BignumDigit twoDigits;
            int start = 0;
            int scan = start + this.Length;

            while (start < scan)
            {
                twoDigits = this [--scan];
                numerator = new BignumDigit (remainder.ToLong (), twoDigits.High);
                remainder = (BignumDigit) (numerator.ToLong () / denominator.ToLong ());
                numerator = new BignumDigit (numerator.ToLong () % denominator.ToLong (), twoDigits.Low);
                this [scan] = new BignumDigit (remainder.ToLong (), numerator.ToLong () / denominator.ToLong ());
                remainder = (BignumDigit) (numerator.ToLong () % denominator.ToLong ());
            }
            return remainder;
        }
Пример #3
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);
            }
        }