示例#1
0
        void SubtractTimes(Bignum other, uint factor)
        {
#if DEBUG
            var a = new Bignum();
            var b = new Bignum();
            a.AssignBignum(this);
            b.AssignBignum(other);
            b.MultiplyByUInt32(factor);
            a.SubtractBignum(b);
#endif
            Debug.Assert(exponent_ <= other.exponent_);
            if (factor < 3)
            {
                for (int i = 0; i < factor; ++i)
                {
                    SubtractBignum(other);
                }

                return;
            }

            uint borrow        = 0;
            int  exponent_diff = other.exponent_ - exponent_;
            for (int i = 0; i < other.used_digits_; ++i)
            {
                ulong product    = factor * other.bigits_[i];
                ulong remove     = borrow + product;
                uint  difference = bigits_[i + exponent_diff] - (uint)(remove & kBigitMask);
                bigits_[i + exponent_diff] = difference & kBigitMask;
                borrow = (uint)((difference >> (kChunkSize - 1)) + (remove >> kBigitSize));
            }

            for (int i = other.used_digits_ + exponent_diff; i < used_digits_; ++i)
            {
                if (borrow == 0)
                {
                    return;
                }
                uint difference = bigits_[i] - borrow;
                bigits_[i] = difference & kBigitMask;
                borrow     = difference >> (kChunkSize - 1);
            }

            Clamp();

#if DEBUG
            Debug.Assert(Equal(a, this));
#endif
        }
示例#2
0
        // This routine multiplies numerator/denominator so that its values lies in the
        // range 1-10. That is after a call to this function we have:
        //    1 <= (numerator + delta_plus) /denominator < 10.
        // Let numerator the input before modification and numerator' the argument
        // after modification, then the output-parameter decimal_point is such that
        //  numerator / denominator * 10^estimated_power ==
        //    numerator' / denominator' * 10^(decimal_point - 1)
        // In some cases estimated_power was too low, and this is already the case. We
        // then simply adjust the power so that 10^(k-1) <= v < 10^k (with k ==
        // estimated_power) but do not touch the numerator or denominator.
        // Otherwise the routine multiplies the numerator and the deltas by 10.
        private static void FixupMultiply10(
            int estimated_power,
            bool is_even,
            out int decimal_point,
            Bignum numerator,
            Bignum denominator,
            Bignum delta_minus,
            Bignum delta_plus)
        {
            bool in_range;

            if (is_even)
            {
                in_range = Bignum.PlusCompare(numerator, delta_plus, denominator) >= 0;
            }
            else
            {
                in_range = Bignum.PlusCompare(numerator, delta_plus, denominator) > 0;
            }
            if (in_range)
            {
                // Since numerator + delta_plus >= denominator we already have
                // 1 <= numerator/denominator < 10. Simply update the estimated_power.
                decimal_point = estimated_power + 1;
            }
            else
            {
                decimal_point = estimated_power;
                numerator.Times10();
                if (Bignum.Equal(delta_minus, delta_plus))
                {
                    delta_minus.Times10();
                    delta_plus.AssignBignum(delta_minus);
                }
                else
                {
                    delta_minus.Times10();
                    delta_plus.Times10();
                }
            }
        }
示例#3
0
        // See comments for InitialScaledStartValues
        private static void InitialScaledStartValuesNegativeExponentNegativePower(
            double v,
            int estimated_power,
            bool need_boundary_deltas,
            Bignum numerator,
            Bignum denominator,
            Bignum delta_minus,
            Bignum delta_plus)
        {
            const ulong kMinimalNormalizedExponent = 0x0010000000000000;

            var   bits        = (ulong)BitConverter.DoubleToInt64Bits(v);
            ulong significand = DoubleHelper.Significand(bits);
            int   exponent    = DoubleHelper.Exponent(bits);
            // Instead of multiplying the denominator with 10^estimated_power we
            // multiply all values (numerator and deltas) by 10^-estimated_power.

            // Use numerator as temporary container for power_ten.
            Bignum power_ten = numerator;

            power_ten.AssignPowerUInt16(10, -estimated_power);

            if (need_boundary_deltas)
            {
                // Since power_ten == numerator we must make a copy of 10^estimated_power
                // before we complete the computation of the numerator.
                // delta_plus = delta_minus = 10^estimated_power
                delta_plus.AssignBignum(power_ten);
                delta_minus.AssignBignum(power_ten);
            }

            // numerator = significand * 2 * 10^-estimated_power
            //  since v = significand * 2^exponent this is equivalent to
            // numerator = v * 10^-estimated_power * 2 * 2^-exponent.
            // Remember: numerator has been abused as power_ten. So no need to assign it
            //  to itself.
            numerator.MultiplyByUInt64(significand);

            // denominator = 2 * 2^-exponent with exponent < 0.
            denominator.AssignUInt16(1);
            denominator.ShiftLeft(-exponent);

            if (need_boundary_deltas)
            {
                // Introduce a common denominator so that the deltas to the boundaries are
                // integers.
                numerator.ShiftLeft(1);
                denominator.ShiftLeft(1);
                // With this shift the boundaries have their correct value, since
                // delta_plus = 10^-estimated_power, and
                // delta_minus = 10^-estimated_power.
                // These assignments have been done earlier.

                // The special case where the lower boundary is twice as close.
                // This time we have to look out for the exception too.
                ulong v_bits = bits;
                if ((v_bits & DoubleHelper.KSignificandMask) == 0 &&
                    // The only exception where a significand == 0 has its boundaries at
                    // "normal" distances:
                    (v_bits & DoubleHelper.KExponentMask) != kMinimalNormalizedExponent)
                {
                    numerator.ShiftLeft(1);   // *2
                    denominator.ShiftLeft(1); // *2
                    delta_plus.ShiftLeft(1);  // *2
                }
            }
        }