public static void NumberToString( double v, DtoaMode mode, int requested_digits, DtoaBuilder builder, out int decimal_point) { var bits = (ulong)BitConverter.DoubleToInt64Bits(v); var significand = DoubleHelper.Significand(bits); var is_even = (significand & 1) == 0; var exponent = DoubleHelper.Exponent(bits); var normalized_exponent = DoubleHelper.NormalizedExponent(significand, exponent); // estimated_power might be too low by 1. var estimated_power = EstimatePower(normalized_exponent); // Shortcut for Fixed. // The requested digits correspond to the digits after the point. If the // number is much too small, then there is no need in trying to get any // digits. if (mode == DtoaMode.Fixed && -estimated_power - 1 > requested_digits) { // Set decimal-point to -requested_digits. This is what Gay does. // Note that it should not have any effect anyways since the string is // empty. decimal_point = -requested_digits; return; } Bignum numerator = new Bignum(); Bignum denominator = new Bignum(); Bignum delta_minus = new Bignum(); Bignum delta_plus = new Bignum(); // Make sure the bignum can grow large enough. The smallest double equals // 4e-324. In this case the denominator needs fewer than 324*4 binary digits. // The maximum double is 1.7976931348623157e308 which needs fewer than // 308*4 binary digits. var need_boundary_deltas = mode == DtoaMode.Shortest; InitialScaledStartValues( v, estimated_power, need_boundary_deltas, numerator, denominator, delta_minus, delta_plus); // We now have v = (numerator / denominator) * 10^estimated_power. FixupMultiply10( estimated_power, is_even, out decimal_point, numerator, denominator, delta_minus, delta_plus); // We now have v = (numerator / denominator) * 10^(decimal_point-1), and // 1 <= (numerator + delta_plus) / denominator < 10 switch (mode) { case DtoaMode.Shortest: GenerateShortestDigits( numerator, denominator, delta_minus, delta_plus, is_even, builder); break; case DtoaMode.Fixed: BignumToFixed( requested_digits, ref decimal_point, numerator, denominator, builder); break; case DtoaMode.Precision: GenerateCountedDigits( requested_digits, ref decimal_point, numerator, denominator, builder); break; default: ExceptionHelper.ThrowArgumentOutOfRangeException(); break; } }
// 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 } } }