// Helper method. private System.Numerics.BigInteger Convert(Jurassic.BigInteger value) { var result = System.Numerics.BigInteger.Zero; for (int i = value.WordCount - 1; i >= 0; i--) { result <<= 32; result += value.Words[i]; } if (value.Sign == -1) { result = result * -1; } return(result); }
/// <summary> /// Multiply by m and add a. /// </summary> /// <param name="b"></param> /// <param name="m"></param> /// <param name="a"></param> /// <returns></returns> public static BigInteger MultiplyAdd(BigInteger b, int m, int a) { if (m <= 0) throw new ArgumentOutOfRangeException("m"); if (a < 0) throw new ArgumentOutOfRangeException("a"); if (b.sign == 0) return new BigInteger(a); uint[] outputBits = new uint[b.wordCount + 1]; int outputWordCount = b.wordCount; uint carry = (uint)a; for (int i = 0; i < b.wordCount; i++) { ulong temp = b.bits[i] * (ulong)m + carry; carry = (uint)(temp >> 32); outputBits[i] = (uint)temp; } if (carry != 0) { outputBits[outputWordCount] = carry; outputWordCount++; } return new BigInteger(outputBits, outputWordCount, 1); }
/// <summary> /// Shifts a BigInteger value a specified number of bits to the right. /// </summary> /// <param name="value"> The value whose bits are to be shifted. </param> /// <param name="shift"> The number of bits to shift <paramref name="value"/> to the right. </param> /// <returns> A value that has been shifted to the right by the specified number of bits. /// Can be negative to shift to the left. </returns> /// <remarks> Note: unlike System.Numerics.BigInteger, negative numbers are treated /// identically to positive numbers. </remarks> public static BigInteger RightShift(BigInteger value, int shift) { // Shifting by zero bits does nothing. if (shift == 0) return value; // Shifting right by a negative number of bits is the same as shifting left. if (shift < 0) return LeftShift(value, -shift); int wordShift = shift / 32; int bitShift = shift - (wordShift * 32); if (wordShift >= value.wordCount) return BigInteger.Zero; uint[] outputBits = new uint[value.wordCount - wordShift]; int outputWordCount = outputBits.Length - 1; uint carry = 0; for (int i = value.wordCount - 1; i >= wordShift; i--) { uint word = value.bits[i]; outputBits[i - wordShift] = (word >> bitShift) | (carry << (32 - bitShift)); carry = word & (((uint)1 << bitShift) - 1); } if (outputBits[outputBits.Length - 1] != 0) outputWordCount++; return new BigInteger(outputBits, outputWordCount, value.sign); }
/// <summary> /// Shifts a BigInteger value a specified number of bits to the left. /// </summary> /// <param name="value"> The value whose bits are to be shifted. </param> /// <param name="shift"> The number of bits to shift <paramref name="value"/> to the left. /// Can be negative to shift to the right. </param> /// <returns> A value that has been shifted to the left by the specified number of bits. </returns> public static BigInteger LeftShift(BigInteger value, int shift) { // Shifting by zero bits does nothing. if (shift == 0) return value; // Shifting left by a negative number of bits is the same as shifting right. if (shift < 0) return RightShift(value, -shift); int wordShift = shift / 32; int bitShift = shift - (wordShift * 32); uint[] outputBits = new uint[value.wordCount + wordShift + 1]; int outputWordCount = outputBits.Length - 1; uint carry = 0; for (int i = 0; i < value.wordCount; i++) { uint word = value.bits[i]; outputBits[i + wordShift] = (word << bitShift) | carry; carry = bitShift == 0 ? 0 : word >> (32 - bitShift); } if (carry != 0) { outputBits[outputWordCount] = carry; outputWordCount++; } return new BigInteger(outputBits, outputWordCount, value.sign); }
/// <summary> /// Negates a specified BigInteger value. /// </summary> /// <param name="value"> The value to negate. </param> /// <returns> The result of the <paramref name="value"/> parameter multiplied by negative /// one (-1). </returns> public static BigInteger Negate(BigInteger value) { value.sign = -value.sign; return(value); }
/// <summary> /// Returns the logarithm of a specified number in a specified base. /// </summary> /// <param name="value"> A number whose logarithm is to be found. </param> /// <param name="baseValue"> The base of the logarithm. </param> /// <returns> The base <paramref name="baseValue"/> logarithm of <paramref name="value"/>. </returns> public static double Log(BigInteger value, double baseValue) { if (baseValue <= 1.0 || double.IsPositiveInfinity(baseValue) || double.IsNaN(baseValue)) throw new ArgumentOutOfRangeException("baseValue", "Unsupported logarithmic base."); if (value.sign < 0) return double.NaN; if (value.sign == 0) return double.NegativeInfinity; if (value.wordCount == 1) return Math.Log((double)value.bits[0], baseValue); double d = 0.0; double residual = 0.5; int bitsInLastWord = 32 - CountLeadingZeroBits(value.bits[value.wordCount - 1]); int bitCount = ((value.wordCount - 1) * 32) + bitsInLastWord; uint highBit = ((uint)1) << (bitsInLastWord - 1); for (int i = value.wordCount - 1; i >= 0; i--) { while (highBit != 0) { if ((value.bits[i] & highBit) != 0) d += residual; residual *= 0.5; highBit = highBit >> 1; } highBit = 0x80000000; } return ((Math.Log(d) + (0.69314718055994529 * bitCount)) / Math.Log(baseValue)); }
/// <summary> /// Calculates the integer result of dividing <paramref name="dividend"/> by /// <paramref name="divisor"/> then sets <paramref name="dividend"/> to the remainder. /// </summary> /// <param name="dividend"> The number that will be divided. </param> /// <param name="divisor"> The number to divide by. </param> /// <returns> The integer that results from dividing <paramref name="dividend"/> by /// <paramref name="divisor"/>. </returns> public static int Quorem(ref BigInteger dividend, BigInteger divisor) { int n = divisor.wordCount; if (dividend.wordCount > n) throw new ArgumentException("b is too large"); if (dividend.wordCount < n) return 0; uint q = dividend.bits[dividend.wordCount - 1] / (divisor.bits[divisor.wordCount - 1] + 1); /* ensure q <= true quotient */ if (q != 0) { ulong borrow = 0; ulong carry = 0; for (int i = 0; i < divisor.wordCount; i++) { ulong ys = divisor.bits[i] * (ulong)q + carry; carry = ys >> 32; ulong y = dividend.bits[i] - (ys & 0xFFFFFFFF) - borrow; borrow = y >> 32 & 1; dividend.bits[i] = (uint)y; } while (dividend.wordCount > 1 && dividend.bits[dividend.wordCount - 1] == 0) dividend.wordCount--; } if (Compare(dividend, divisor) >= 0) { q++; ulong borrow = 0; ulong carry = 0; for (int i = 0; i < divisor.wordCount; i++) { ulong ys = divisor.bits[i] + carry; carry = ys >> 32; ulong y = dividend.bits[i] - (ys & 0xFFFFFFFF) - borrow; borrow = y >> 32 & 1; dividend.bits[i] = (uint)y; } while (dividend.wordCount > 1 && dividend.bits[dividend.wordCount - 1] == 0) dividend.wordCount--; } if (dividend.wordCount == 1 && dividend.bits[0] == 0) dividend.sign = 0; return (int)q; }
/// <summary> /// Negates a specified BigInteger value. /// </summary> /// <param name="value"> The value to negate. </param> /// <returns> The result of the <paramref name="value"/> parameter multiplied by negative /// one (-1). </returns> public static BigInteger Negate(BigInteger value) { value.sign = -value.sign; return value; }
/// <summary> /// Modifies the initial estimate until the closest double-precision number to the desired /// value is found. /// </summary> /// <param name="initialEstimate"> The initial estimate. Assumed to be very close to the /// result. </param> /// <param name="base10Exponent"> The power-of-ten scale factor. </param> /// <param name="desiredValue"> The desired value, already scaled using the power-of-ten /// scale factor. </param> /// <returns> The closest double-precision number to the desired value. If there are two /// such values, the one with the least significant bit set to zero is returned. </returns> private static double RefineEstimate(double initialEstimate, int base10Exponent, BigInteger desiredValue) { // Numbers with 16 digits or more are tricky because rounding error can cause the // result to be out by one or more ULPs (units in the last place). // The algorithm is as follows: // 1. Use the initially calculated result as an estimate. // 2. Create a second estimate by modifying the estimate by one ULP. // 3. Calculate the actual value of both estimates to precision X (using arbitrary // precision arithmetic). // 4. If they are both above the desired value then decrease the estimates by 1 // ULP and goto step 3. // 5. If they are both below the desired value then increase up the estimates by // 1 ULP and goto step 3. // 6. One estimate must now be above the desired value and one below. // 7. If one is estimate is clearly closer to the desired value than the other, // then return that estimate. // 8. Increase the precision by 32 bits. // 9. If the precision is less than or equal to 160 bits goto step 3. // 10. Assume that the estimates are equally close to the desired value; return the // value with the least significant bit equal to 0. int direction = double.IsPositiveInfinity(initialEstimate) ? -1 : 1; int precision = 32; // Calculate the candidate value by modifying the last bit. double result = initialEstimate; double result2 = AddUlps(result, direction); // Figure out our multiplier. Either base10Exponent is positive, in which case we // multiply actual1 and actual2, or it's negative, in which case we multiply // desiredValue. BigInteger multiplier = BigInteger.One; if (base10Exponent < 0) multiplier = BigInteger.Pow(10, -base10Exponent); else if (base10Exponent > 0) desiredValue = BigInteger.Multiply(desiredValue, BigInteger.Pow(10, base10Exponent)); while (precision <= 160) { // Scale the candidate values to a big integer. var actual1 = ScaleToInteger(result, multiplier, precision); var actual2 = ScaleToInteger(result2, multiplier, precision); // Calculate the differences between the candidate values and the desired value. var baseline = BigInteger.LeftShift(desiredValue, precision); var diff1 = BigInteger.Subtract(actual1, baseline); var diff2 = BigInteger.Subtract(actual2, baseline); if (diff1.Sign == direction && diff2.Sign == direction) { // We're going the wrong way! direction = -direction; result2 = AddUlps(result, direction); } else if (diff1.Sign == -direction && diff2.Sign == -direction) { // Going the right way, but need to go further. result = result2; result2 = AddUlps(result, direction); } else { // Found two values that bracket the actual value. // If one candidate value is closer to the actual value by at least 2 (one // doesn't cut it because of the integer division) then use that value. diff1 = BigInteger.Abs(diff1); diff2 = BigInteger.Abs(diff2); if (BigInteger.Compare(diff1, BigInteger.Subtract(diff2, BigInteger.One)) < 0) return result; if (BigInteger.Compare(diff2, BigInteger.Subtract(diff1, BigInteger.One)) < 0) return result2; // Not enough precision to determine the correct answer, or it's a halfway case. // Increase the precision. precision += 32; } // If result2 is NaN then we have gone too far. if (double.IsNaN(result2) == true) return result; } // Even with heaps of precision there is no clear winner. // Assume this is a halfway case: choose the floating-point value with its least // significant bit equal to 0. return (XBitConverter.DoubleToInt64Bits(result) & 1) == 0 ? result : result2; }
/// <summary> /// Parses a number and returns the corresponding double-precision value. /// </summary> /// <param name="reader"> The reader to read characters from. </param> /// <param name="firstChar"> The first character of the number. Must be 0-9 or a period. </param> /// <param name="status"> Upon returning, contains the type of error if one occurred. </param> /// <param name="allowHex"> </param> /// <param name="allowOctal"> </param> /// <returns> The numeric value, or <c>NaN</c> if the number is invalid. </returns> internal static double ParseCore(TextReader reader, char firstChar, out ParseCoreStatus status, bool allowHex = true, bool allowOctal = true) { double result; // A count of the number of integral and fractional digits of the input number. int totalDigits = 0; // Assume success. status = ParseCoreStatus.Success; // If the number starts with '0' then the number is a hex literal or a octal literal. if (firstChar == '0' && (allowHex == true || allowOctal == true)) { // Read the next char - should be 'x' or 'X' if this is a hex number (could be just '0'). int c = reader.Peek(); if ((c == 'x' || c == 'X') && allowHex == true) { // Hex number. reader.Read(); result = ParseHex(reader); if (double.IsNaN(result) == true) { status = ParseCoreStatus.InvalidHexLiteral; return double.NaN; } status = ParseCoreStatus.HexLiteral; return result; } else if (c >= '0' && c <= '9' && allowOctal == true) { // Octal number. result = ParseOctal(reader); if (double.IsNaN(result) == true) { status = ParseCoreStatus.InvalidOctalLiteral; return double.NaN; } status = ParseCoreStatus.OctalLiteral; return result; } } // desired1-3 hold the integral and fractional digits of the input number. // desired1 holds the first set of nine digits, desired2 holds the second set of nine // digits, desired3 holds the rest. int desired1 = 0; int desired2 = 0; var desired3 = BigInteger.Zero; // Indicates the base-10 scale factor of the output e.g. the result is // desired x 10^exponentBase10. int exponentBase10 = 0; // Read the integer component. if (firstChar >= '0' && firstChar <= '9') { desired1 = firstChar - '0'; totalDigits = 1; while (true) { int c = reader.Peek(); if (c < '0' || c > '9') break; reader.Read(); if (totalDigits < 9) desired1 = desired1 * 10 + (c - '0'); else if (totalDigits < 18) desired2 = desired2 * 10 + (c - '0'); else desired3 = BigInteger.MultiplyAdd(desired3, 10, c - '0'); totalDigits++; } } if (firstChar == '.' || reader.Peek() == '.') { // Skip past the period. if (firstChar != '.') reader.Read(); // Read the fractional component. int fractionalDigits = 0; while (true) { int c = reader.Peek(); if (c < '0' || c > '9') break; reader.Read(); if (totalDigits < 9) desired1 = desired1 * 10 + (c - '0'); else if (totalDigits < 18) desired2 = desired2 * 10 + (c - '0'); else desired3 = BigInteger.MultiplyAdd(desired3, 10, c - '0'); totalDigits++; fractionalDigits++; exponentBase10--; } // Check if the number consists solely of a period. if (totalDigits == 0) { status = ParseCoreStatus.NoDigits; return double.NaN; } // Check if the number has a period but no digits afterwards. if (fractionalDigits == 0) status = ParseCoreStatus.NoFraction; } if (reader.Peek() == 'e' || reader.Peek() == 'E') { // Skip past the 'e'. reader.Read(); // Read the sign of the exponent. bool exponentNegative = false; int c = reader.Peek(); if (c == '+') reader.Read(); else if (c == '-') { reader.Read(); exponentNegative = true; } // Read the first character of the exponent. int firstExponentChar = reader.Read(); // Check there is a number after the 'e'. int exponent = 0; if (firstExponentChar < '0' || firstExponentChar > '9') { status = ParseCoreStatus.NoExponent; } else { // Read the rest of the exponent. exponent = firstExponentChar - '0'; int exponentDigits = 1; while (true) { c = reader.Peek(); if (c < '0' || c > '9') break; reader.Read(); exponent = Math.Min(exponent * 10 + (c - '0'), 9999); exponentDigits++; } // JSON does not allow a leading zero in front of the exponent. if (firstExponentChar == '0' && exponentDigits > 1 && status == ParseCoreStatus.Success) status = ParseCoreStatus.ExponentHasLeadingZero; } // Keep track of the overall base-10 exponent. exponentBase10 += exponentNegative ? -exponent : exponent; } // Calculate the integral and fractional portion of the number, scaled to an integer. if (totalDigits < 16) { // Combine desired1 and desired2 to produce an integer representing the final // result. result = (double)((long)desired1 * integerPowersOfTen[Math.Max(totalDigits - 9, 0)] + desired2); } else { // Combine desired1, desired2 and desired3 to produce an integer representing the // final result. var temp = desired3; desired3 = new BigInteger((long)desired1 * integerPowersOfTen[Math.Min(totalDigits - 9, 9)] + desired2); if (totalDigits > 18) { desired3 = BigInteger.Multiply(desired3, BigInteger.Pow(10, totalDigits - 18)); desired3 = BigInteger.Add(desired3, temp); } result = desired3.ToDouble(); } // Apply the base-10 exponent. if (exponentBase10 > 0) result *= Math.Pow(10, exponentBase10); else if (exponentBase10 < 0 && exponentBase10 >= -308) result /= Math.Pow(10, -exponentBase10); else if (exponentBase10 < -308) { // Note: 10^308 is the largest representable power of ten. result /= Math.Pow(10, 308); result /= Math.Pow(10, -exponentBase10 - 308); } // Numbers with 16 or more digits require the use of arbitrary precision arithmetic to // determine the correct answer. if (totalDigits >= 16) return RefineEstimate(result, exponentBase10, desired3); return result; }
// Helper method. private System.Numerics.BigInteger Convert(BigInteger value) { var result = System.Numerics.BigInteger.Zero; for (int i = value.WordCount - 1; i >= 0; i--) { result <<= 32; result += value.Words[i]; } if (value.Sign == -1) result = result * -1; return result; }
/// <summary> /// Converts a number to a string. /// </summary> /// <param name="value"> The value to convert to a string. </param> /// <param name="radix"> The base of the number system to convert to. </param> /// <param name="style"> The type of formatting to apply. </param> /// <param name="precision"> /// This value is dependent on the formatting style: /// Regular - this value has no meaning. /// Precision - the number of significant figures to display. /// Fixed - the number of figures to display after the decimal point. /// Exponential - the number of figures to display after the decimal point. /// </param> internal static string ToString(double value, int radix, Style style, int precision = 0) { // Handle NaN. if (double.IsNaN(value)) return "NaN"; // Handle zero. if (value == 0.0) { switch (style) { case Style.Regular: return "0"; case Style.Precision: return "0." + new string('0', precision - 1); case Style.Fixed: if (precision == 0) return "0"; return "0." + new string('0', precision); case Style.Exponential: if (precision <= 0) return "0e+0"; return string.Format("0.{0}e+0", new string('0', precision)); } } var result = new System.Text.StringBuilder(18); // Handle negative numbers. if (value < 0.0) { value = -value; result.Append('-'); } // Handle infinity. if (double.IsPositiveInfinity(value)) { result.Append("Infinity"); return result.ToString(); } // Extract the base-2 exponent. var bits = new DoubleBits() { DoubleValue = value }; int base2Exponent = (int)(bits.LongValue >> MantissaExplicitBits); // Extract the mantissa. long mantissa = bits.LongValue & MantissaMask; // Correct the base-2 exponent. if (base2Exponent == 0) { // This is a denormalized number. base2Exponent = base2Exponent - ExponentBias - MantissaExplicitBits + 1; } else { // This is a normal number. base2Exponent = base2Exponent - ExponentBias - MantissaExplicitBits; // Add the implicit bit. mantissa |= MantissaImplicitBit; } // Remove any trailing zeros. int trailingZeroBits = CountTrailingZeroBits((ulong)mantissa); mantissa >>= trailingZeroBits; base2Exponent += trailingZeroBits; // Calculate the logarithm of the number. int exponent; if (radix == 10) { exponent = (int)Math.Floor(Math.Log10(value)); // We need to calculate k = floor(log10(x)). // log(x) ~=~ log(1.5) + (x-1.5)/1.5 (taylor series approximation) // log10(x) ~=~ log(1.5) / log(10) + (x - 1.5) / (1.5 * log(10)) // d = x * 2^l (1 <= x < 2) // log10(d) = l * log10(2) + log10(x) // log10(d) ~=~ l * log10(2) + (x - 1.5) * (1 / (1.5 * log(10))) + log(1.5) / log(10) // log10(d) ~=~ l * 0.301029995663981 + (x - 1.5) * 0.289529654602168 + 0.1760912590558 // The last term (0.1760912590558) is rounded so that k = floor(log10(x)) or // k = floor(log10(x)) + 1 (i.e. it's the exact value or one higher). //double log10; //if ((int)(bits.LongValue >> MantissaExplicitBits) == 0) //{ // // The number is denormalized. // int mantissaShift = CountLeadingZeroBits((ulong)mantissa) - (64 - MantissaImplicitBits); // bits.LongValue = (mantissa << mantissaShift) & MantissaMask | // ((long)ExponentBias << MantissaExplicitBits); // // Calculate an overestimate of log-10 of the value. // log10 = (bits.DoubleValue - 1.5) * 0.289529654602168 + 0.1760912590558 + // (base2Exponent - mantissaShift) * 0.301029995663981; //} //else //{ // // Set the base-2 exponent to biased zero. // bits.LongValue = (bits.LongValue & ~ExponentMask) | ((long)ExponentBias << MantissaExplicitBits); // // Calculate an overestimate of log-10 of the value. // log10 = (bits.DoubleValue - 1.5) * 0.289529654602168 + 0.1760912590558 + base2Exponent * 0.301029995663981; //} //// (int)Math.Floor(log10) //exponent = (int)log10; //if (log10 < 0 && log10 != exponent) // exponent--; //if (exponent >= 0 && exponent < tens.Length) //{ // if (value < tens[exponent]) // exponent--; //} } else exponent = (int)Math.Floor(Math.Log(value, radix)); if (radix == 10 && style == Style.Regular) { // Do we have a small integer? if (base2Exponent >= 0 && exponent <= 14) { // Yes. for (int i = exponent; i >= 0; i--) { double scaleFactor = tens[i]; int digit = (int)(value / scaleFactor); result.Append((char)(digit + '0')); value -= digit * scaleFactor; } return result.ToString(); } } // toFixed acts like toString() if the exponent is >= 21. if (style == Style.Fixed && exponent >= 21) style = Style.Regular; // Calculate the exponent thresholds. int lowExponentThreshold = int.MinValue; if (radix == 10 && style != Style.Fixed) lowExponentThreshold = -7; if (style == Style.Exponential) lowExponentThreshold = -1; int highExponentThreshold = int.MaxValue; if (radix == 10 && style == Style.Regular) highExponentThreshold = 21; if (style == Style.Precision) highExponentThreshold = precision; if (style == Style.Exponential) highExponentThreshold = 0; // Calculate the number of bits per digit. double bitsPerDigit = radix == 10 ? 3.322 : Math.Log(radix, 2); // Calculate the maximum number of digits to output. // We add 7 so that there is enough precision to distinguish halfway numbers. int maxDigitsToOutput = radix == 10 ? 22 : (int)Math.Floor(53 / bitsPerDigit) + 7; // Calculate the number of integral digits, or if negative, the number of zeros after // the decimal point. int integralDigits = exponent + 1; // toFixed with a low precision causes rounding. if (style == Style.Fixed && precision <= -integralDigits) { int diff = (-integralDigits) - (precision - 1); maxDigitsToOutput += diff; exponent += diff; integralDigits += diff; } // Output any leading zeros. bool decimalPointOutput = false; if (integralDigits <= 0 && integralDigits > lowExponentThreshold + 1) { result.Append('0'); if (integralDigits < 0) { result.Append('.'); decimalPointOutput = true; result.Append('0', -integralDigits); } } // We need to calculate the integers "scaledValue" and "divisor" such that: // value = scaledValue / divisor * 10 ^ exponent // 1 <= scaledValue / divisor < 10 BigInteger scaledValue = new BigInteger(mantissa); BigInteger divisor = BigInteger.One; BigInteger multiplier = BigInteger.One; if (exponent > 0) { // Number is >= 10. divisor = BigInteger.Multiply(divisor, BigInteger.Pow(radix, exponent)); } else if (exponent < 0) { // Number is < 1. multiplier = BigInteger.Pow(radix, -exponent); scaledValue = BigInteger.Multiply(scaledValue, multiplier); } // Scale the divisor so it is 74 bits ((21 digits + 1 digit for rounding) * approx 3.322 bits per digit). int powerOfTwoScaleFactor = (radix == 10 ? 74 : (int)Math.Ceiling(maxDigitsToOutput * bitsPerDigit)) - divisor.BitCount; divisor = BigInteger.LeftShift(divisor, powerOfTwoScaleFactor); scaledValue = BigInteger.LeftShift(scaledValue, powerOfTwoScaleFactor + base2Exponent); // Calculate the error. BigInteger errorDelta = BigInteger.Zero; int errorPowerOfTen = int.MinValue; switch (style) { case Style.Regular: errorDelta = ScaleToInteger(CalculateError(value), multiplier, powerOfTwoScaleFactor - 1); break; case Style.Precision: errorPowerOfTen = integralDigits - precision; break; case Style.Fixed: errorPowerOfTen = -precision; break; case Style.Exponential: if (precision < 0) errorDelta = ScaleToInteger(CalculateError(value), multiplier, powerOfTwoScaleFactor - 1); else errorPowerOfTen = integralDigits - precision - 1; break; default: throw new ArgumentException("Unknown formatting style.", "style"); } if (errorPowerOfTen != int.MinValue) { errorDelta = multiplier; if (errorPowerOfTen > 0) errorDelta = BigInteger.Multiply(errorDelta, BigInteger.Pow(radix, errorPowerOfTen)); errorDelta = BigInteger.LeftShift(errorDelta, powerOfTwoScaleFactor - 1); if (errorPowerOfTen < 0) { // We would normally divide by the power of 10 here, but division is extremely // slow so we multiply everything else instead. //errorDelta = BigInteger.Divide(errorDelta, BigInteger.Pow(radix, -errorPowerOfTen)); var errorPowerOfTenMultiplier = BigInteger.Pow(radix, -errorPowerOfTen); scaledValue = BigInteger.Multiply(scaledValue, errorPowerOfTenMultiplier); divisor = BigInteger.Multiply(divisor, errorPowerOfTenMultiplier); BigInteger.SetupQuorum(ref scaledValue, ref divisor, ref errorDelta); } } // Shrink the error in the case where ties are resolved towards the value with the // least significant bit set to zero. if ((BitConverter.DoubleToInt64Bits(value) & 1) == 1) errorDelta.InPlaceDecrement(); // Cache half the divisor. BigInteger halfDivisor = BigInteger.RightShift(divisor, 1); // Output the digits. int zeroCount = 0; int digitsOutput = 0; bool rounded = false, scientificNotation = false; for (; digitsOutput < maxDigitsToOutput && rounded == false; digitsOutput++) { // Calculate the next digit. var digit = (int)BigInteger.Quorem(ref scaledValue, divisor); if (BigInteger.Compare(scaledValue, errorDelta) <= 0 && BigInteger.Compare(scaledValue, halfDivisor) < 0) { // Round down. rounded = true; } else if (BigInteger.Compare(BigInteger.Subtract(divisor, scaledValue), errorDelta) <= 0) { // Round up. rounded = true; digit++; if (digit == radix) { digit = 1; exponent++; integralDigits++; } } if (digit > 0 || decimalPointOutput == false) { // Check if the decimal point should be output. if (decimalPointOutput == false && (scientificNotation == true || digitsOutput == integralDigits)) { result.Append('.'); decimalPointOutput = true; } // Output any pent-up zeros. if (zeroCount > 0) { result.Append('0', zeroCount); zeroCount = 0; } // Output the next digit. if (digit < 10) result.Append((char)(digit + '0')); else result.Append((char)(digit - 10 + 'a')); } else zeroCount++; // Check whether the number should be displayed in scientific notation (we cannot // determine this up front for large exponents because the number might get rounded // up to cross the threshold). if (digitsOutput == 0 && (exponent <= lowExponentThreshold || exponent >= highExponentThreshold)) scientificNotation = true; scaledValue = BigInteger.MultiplyAdd(scaledValue, radix, 0); errorDelta = BigInteger.MultiplyAdd(errorDelta, radix, 0); } // Add any extra zeros on the end, if necessary. if (scientificNotation == false && integralDigits > digitsOutput) { result.Append('0', integralDigits - digitsOutput); digitsOutput = integralDigits; } // Most of the styles output redundent zeros. int redundentZeroCount = 0; switch (style) { case Style.Precision: redundentZeroCount = zeroCount + precision - digitsOutput; break; case Style.Fixed: redundentZeroCount = precision - (digitsOutput - zeroCount - integralDigits); break; case Style.Exponential: redundentZeroCount = precision - (digitsOutput - zeroCount) + 1; break; } if (redundentZeroCount > 0) { if (decimalPointOutput == false) result.Append('.'); result.Append('0', redundentZeroCount); } if (scientificNotation == true) { // Add the exponent on the end. result.Append('e'); if (exponent > 0) result.Append('+'); result.Append(exponent); } return result.ToString(); }
/// <summary> /// Gets the absolute value of a BigInteger object. /// </summary> /// <param name="value"> A number. </param> /// <returns> The absolute value of <paramref name="value"/> </returns> public static BigInteger Abs(BigInteger b) { return(new BigInteger(b.bits, b.wordCount, Math.Abs(b.sign))); }
/// <summary> /// Modifies the given values so they are suitable for passing to Quorem. /// </summary> /// <param name="dividend"> The number that will be divided. </param> /// <param name="divisor"> The number to divide by. </param> /// <param name="other"> Another value involved in the division. </param> public static void SetupQuorum(ref BigInteger dividend, ref BigInteger divisor, ref BigInteger other) { var leadingZeroCount = CountLeadingZeroBits(divisor.bits[divisor.wordCount - 1]); if (leadingZeroCount < 4 || leadingZeroCount > 28) { dividend = BigInteger.LeftShift(dividend, 8); divisor = BigInteger.LeftShift(divisor, 8); other = BigInteger.LeftShift(other, 8); } }
/// <summary> /// Computes b x 5 ^ k. /// </summary> /// <param name="b"></param> /// <param name="k"></param> /// <returns></returns> public static BigInteger MultiplyPow5(BigInteger b, int k) { BigInteger p5; // Fast route if k <= 3. if ((k & 3) != 0) b = MultiplyAdd(b, powersOfFive[(k & 3) - 1], 0); if ((k >>= 2) == 0) return b; p5 = new BigInteger(625); while (true) { if ((k & 1) == 1) b = Multiply(b, p5); if ((k >>= 1) == 0) break; p5 = Multiply(p5, p5); } return b; }
/// <summary> /// Returns <c>-1</c> if a < b, <c>0</c> if they are the same, or <c>1</c> if a > b. /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <returns></returns> public static int Compare(BigInteger a, BigInteger b) { if (a.sign != b.sign) return a.sign < b.sign ? -1 : 1; if (a.sign > 0) { // Comparison of positive numbers. if (a.wordCount < b.wordCount) return -1; if (a.wordCount > b.wordCount) return 1; for (int i = a.wordCount - 1; i >= 0; i--) { if (a.bits[i] != b.bits[i]) return a.bits[i] < b.bits[i] ? -1 : 1; } } else if (a.sign < 0) { // Comparison of negative numbers. if (a.wordCount < b.wordCount) return 1; if (a.wordCount > b.wordCount) return -1; for (int i = a.wordCount - 1; i >= 0; i--) { if (a.bits[i] != b.bits[i]) return a.bits[i] < b.bits[i] ? 1 : -1; } } return 0; }
/// <summary> /// Scales the given double-precision number by multiplying and then shifting it. /// </summary> /// <param name="value"> The value to scale. </param> /// <param name="multiplier"> The multiplier. </param> /// <param name="shift"> The power of two scale factor. </param> /// <returns> A BigInteger containing the result of multiplying <paramref name="value"/> by /// <paramref name="multiplier"/> and then shifting left by <paramref name="shift"/> bits. </returns> private static BigInteger ScaleToInteger(double value, BigInteger multiplier, int shift) { long bits = XBitConverter.DoubleToInt64Bits(value); // Extract the base-2 exponent. var base2Exponent = (int)((bits & 0x7FF0000000000000) >> 52) - 1023; // Extract the mantissa. long mantissa = bits & 0xFFFFFFFFFFFFF; if (base2Exponent > -1023) { mantissa |= 0x10000000000000; base2Exponent -= 52; } else { // Denormals. base2Exponent -= 51; } // Extract the sign bit. if (bits < 0) mantissa = -mantissa; var result = new BigInteger(mantissa); result = BigInteger.Multiply(result, multiplier); shift += base2Exponent; result = BigInteger.LeftShift(result, shift); return result; }
/// <summary> /// Returns the product of two BigInteger values. /// </summary> /// <param name="left"> The first number to multiply. </param> /// <param name="right"> The second number to multiply. </param> /// <returns> The product of the <paramref name="left"/> and <paramref name="right"/> /// parameters. </returns> public static BigInteger Multiply(BigInteger left, BigInteger right) { // Check for special cases. if (left.wordCount == 1) { // 0 * right = 0 if (left.bits[0] == 0) return BigInteger.Zero; // 1 * right = right // -1 * right = -right if (left.bits[0] == 1) return left.sign == -1 ? Negate(right) : right; } if (right.wordCount == 1) { // left * 0 = 0 if (right.bits[0] == 0) return BigInteger.Zero; // left * 1 = left // left * -1 = -left if (right.bits[0] == 1) return right.sign == -1 ? Negate(left) : left; } uint[] outputBits = new uint[left.wordCount + right.wordCount]; int outputWordCount = left.wordCount + right.wordCount - 1; for (int i = 0; i < left.wordCount; i++) { uint carry = 0; for (int j = 0; j < right.wordCount; j++) { ulong temp = (ulong)left.bits[i] * right.bits[j] + outputBits[i + j] + carry; carry = (uint)(temp >> 32); outputBits[i + j] = (uint)temp; } if (carry != 0) { outputWordCount = Math.Max(outputWordCount, i + right.wordCount + 1); outputBits[i + right.wordCount] = (uint)carry; } } while (outputWordCount > 1 && outputBits[outputWordCount - 1] == 0) outputWordCount--; return new BigInteger(outputBits, outputWordCount, left.sign * right.sign); }
/// <summary> /// Gets the absolute value of a BigInteger object. /// </summary> /// <param name="value"> A number. </param> /// <returns> The absolute value of <paramref name="value"/> </returns> public static BigInteger Abs(BigInteger b) { return new BigInteger(b.bits, b.wordCount, Math.Abs(b.sign)); }
/// <summary> /// Subtracts one BigInteger value from another and returns the result. /// </summary> /// <param name="left"> The value to subtract from. </param> /// <param name="right"> The value to subtract. </param> /// <returns> The result of subtracting <paramref name="right"/> from /// <paramref name="left"/>. </returns> public static BigInteger Subtract(BigInteger left, BigInteger right) { // 0 - right = -right if (left.Sign == 0) return Negate(right); // left - 0 = left if (right.Sign == 0) return left; // If the signs of the two numbers are different, do an add instead. if (left.Sign != right.Sign) return Add(left, Negate(right)); // From here the sign of both numbers is the same. uint[] outputBits = new uint[Math.Max(left.wordCount, right.wordCount)]; int outputWordCount = outputBits.Length; int outputSign = left.sign; int i; // Arrange it so that Abs(a) > Abs(b). bool swap = false; if (left.wordCount < right.wordCount) swap = true; else if (left.wordCount == right.wordCount) { for (i = left.wordCount - 1; i >= 0; i--) if (left.bits[i] != right.bits[i]) { if (left.bits[i] < right.bits[i]) swap = true; break; } } if (swap == true) { var temp = left; left = right; right = temp; outputSign = -outputSign; } ulong y, borrow = 0; for (i = 0; i < right.wordCount; i++) { y = (ulong)left.bits[i] - right.bits[i] - borrow; borrow = y >> 32 & 1; outputBits[i] = (uint)y; } for (; i < left.wordCount; i++) { y = (ulong)left.bits[i] - borrow; borrow = y >> 32 & 1; outputBits[i] = (uint)y; } while (outputWordCount > 1 && outputBits[outputWordCount - 1] == 0) outputWordCount--; return new BigInteger(outputBits, outputWordCount, outputSign); }
/// <summary> /// Adds two BigInteger values and returns the result. /// </summary> /// <param name="left"> The first value to add. </param> /// <param name="right"> The second value to add. </param> /// <returns> The sum of <paramref name="left"/> and <paramref name="right"/>. </returns> public static BigInteger Add(BigInteger left, BigInteger right) { // 0 + right = right if (left.Sign == 0) return right; // left + 0 = left if (right.Sign == 0) return left; // If the signs of the two numbers are different, do a subtract instead. if (left.Sign != right.Sign) return Subtract(left, Negate(right)); // From here the sign of both numbers is the same. int outputWordCount = Math.Max(left.wordCount, right.wordCount); uint[] outputBits = new uint[outputWordCount + 1]; uint borrow = 0; int i = 0; for (; i < Math.Min(left.wordCount, right.wordCount); i++) { ulong temp = (ulong)left.bits[i] + right.bits[i] + borrow; borrow = (uint)(temp >> 32); outputBits[i] = (uint)temp; } if (left.wordCount > right.wordCount) { for (; i < left.wordCount; i++) { ulong temp = (ulong)left.bits[i] + borrow; borrow = (uint)(temp >> 32); outputBits[i] = (uint)temp; } } else if (left.wordCount < right.wordCount) { for (; i < right.wordCount; i++) { ulong temp = (ulong)right.bits[i] + borrow; borrow = (uint)(temp >> 32); outputBits[i] = (uint)temp; } } if (borrow != 0) { outputBits[outputWordCount] = borrow; outputWordCount++; } return new BigInteger(outputBits, outputWordCount, left.Sign); }
/// <summary> /// Subtracts one BigInteger value from another and returns the result. /// </summary> /// <param name="left"> The value to subtract from. </param> /// <param name="right"> The value to subtract. </param> /// <returns> The result of subtracting <paramref name="right"/> from /// <paramref name="left"/>. </returns> public static BigInteger Subtract(BigInteger left, BigInteger right) { // 0 - right = -right if (left.Sign == 0) { return(Negate(right)); } // left - 0 = left if (right.Sign == 0) { return(left); } // If the signs of the two numbers are different, do an add instead. if (left.Sign != right.Sign) { return(Add(left, Negate(right))); } // From here the sign of both numbers is the same. uint[] outputBits = new uint[Math.Max(left.wordCount, right.wordCount)]; int outputWordCount = outputBits.Length; int outputSign = left.sign; int i; // Arrange it so that Abs(a) > Abs(b). bool swap = false; if (left.wordCount < right.wordCount) { swap = true; } else if (left.wordCount == right.wordCount) { for (i = left.wordCount - 1; i >= 0; i--) { if (left.bits[i] != right.bits[i]) { if (left.bits[i] < right.bits[i]) { swap = true; } break; } } } if (swap == true) { var temp = left; left = right; right = temp; outputSign = -outputSign; } ulong y, borrow = 0; for (i = 0; i < right.wordCount; i++) { y = (ulong)left.bits[i] - right.bits[i] - borrow; borrow = y >> 32 & 1; outputBits[i] = (uint)y; } for (; i < left.wordCount; i++) { y = (ulong)left.bits[i] - borrow; borrow = y >> 32 & 1; outputBits[i] = (uint)y; } while (outputWordCount > 1 && outputBits[outputWordCount - 1] == 0) { outputWordCount--; } return(new BigInteger(outputBits, outputWordCount, outputSign)); }