// See comments for InitialScaledStartValues private static void InitialScaledStartValuesNegativeExponentPositivePower( double v, int estimated_power, bool need_boundary_deltas, Bignum numerator, Bignum denominator, Bignum delta_minus, Bignum delta_plus) { var bits = (ulong)BitConverter.DoubleToInt64Bits(v); ulong significand = DoubleHelper.Significand(bits); int exponent = DoubleHelper.Exponent(bits); // v = f * 2^e with e < 0, and with estimated_power >= 0. // This means that e is close to 0 (have a look at how estimated_power is // computed). // numerator = significand // since v = significand * 2^exponent this is equivalent to // numerator = v * / 2^-exponent numerator.AssignUInt64(significand); // denominator = 10^estimated_power * 2^-exponent (with exponent < 0) denominator.AssignPowerUInt16(10, estimated_power); denominator.ShiftLeft(-exponent); if (need_boundary_deltas) { // Introduce a common denominator so that the deltas to the boundaries are // integers. denominator.ShiftLeft(1); numerator.ShiftLeft(1); // Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common // denominator (of 2) delta_plus equals 2^e. // Given that the denominator already includes v's exponent the distance // to the boundaries is simply 1. delta_plus.AssignUInt16(1); // Same for delta_minus (with adjustments below if f == 2^p-1). delta_minus.AssignUInt16(1); // If the significand (without the hidden bit) is 0, then the lower // boundary is closer than just one ulp (unit in the last place). // There is only one exception: if the next lower number is a denormal // then the distance is 1 ulp. Since the exponent is close to zero // (otherwise estimated_power would have been negative) this cannot happen // here either. ulong v_bits = bits; if ((v_bits & DoubleHelper.KSignificandMask) == 0) { // The lower boundary is closer at half the distance of "normal" numbers. // Increase the denominator and adapt all but the delta_minus. denominator.ShiftLeft(1); // *2 numerator.ShiftLeft(1); // *2 delta_plus.ShiftLeft(1); // *2 } } }
// See comments for InitialScaledStartValues. private static void InitialScaledStartValuesPositiveExponent( double v, int estimated_power, bool need_boundary_deltas, Bignum numerator, Bignum denominator, Bignum delta_minus, Bignum delta_plus) { // A positive exponent implies a positive power. Debug.Assert(estimated_power >= 0); // Since the estimated_power is positive we simply multiply the denominator // by 10^estimated_power. // numerator = v. var bits = (ulong)BitConverter.DoubleToInt64Bits(v); numerator.AssignUInt64(DoubleHelper.Significand(bits)); numerator.ShiftLeft(DoubleHelper.Exponent(bits)); // denominator = 10^estimated_power. denominator.AssignPowerUInt16(10, estimated_power); if (need_boundary_deltas) { // Introduce a common denominator so that the deltas to the boundaries are // integers. denominator.ShiftLeft(1); numerator.ShiftLeft(1); // Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common // denominator (of 2) delta_plus equals 2^e. delta_plus.AssignUInt16(1); delta_plus.ShiftLeft(DoubleHelper.Exponent(bits)); // Same for delta_minus (with adjustments below if f == 2^p-1). delta_minus.AssignUInt16(1); delta_minus.ShiftLeft(DoubleHelper.Exponent(bits)); // If the significand (without the hidden bit) is 0, then the lower // boundary is closer than just half a ulp (unit in the last place). // There is only one exception: if the next lower number is a denormal then // the distance is 1 ulp. This cannot be the case for exponent >= 0 (but we // have to test it in the other function where exponent < 0). ulong v_bits = bits; if ((v_bits & DoubleHelper.KSignificandMask) == 0) { // The lower boundary is closer at half the distance of "normal" numbers. // Increase the common denominator and adapt all but the delta_minus. denominator.ShiftLeft(1); // *2 numerator.ShiftLeft(1); // *2 delta_plus.ShiftLeft(1); // *2 } } }
// 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 } } }