private static EInteger FromRadixSubstringGeneral( string cs, int radix, int index, int endIndex, bool negative) { if (endIndex - index > 72) { int midIndex = index + ((endIndex - index) / 2); EInteger eia = FromRadixSubstringGeneral( cs, radix, index, midIndex, false); // DebugUtility.Log("eia="+eia); EInteger eib = FromRadixSubstringGeneral( cs, radix, midIndex, endIndex, false); // DebugUtility.Log("eib="+eib); EInteger mult = null; int intpow = endIndex - midIndex; if (radix == 10) { eia = NumberUtility.MultiplyByPowerOfFive(eia, intpow).ShiftLeft(intpow); } else if (radix == 5) { eia = NumberUtility.MultiplyByPowerOfFive(eia, intpow); } else { mult = EInteger.FromInt32(radix).Pow(endIndex - midIndex); eia = eia.Multiply(mult); } eia = eia.Add(eib); // DebugUtility.Log("index={0} {1} {2} [pow={3}] [pow={4} ms, muladd={5} ms]", // index, midIndex, endIndex, endIndex-midIndex, swPow.ElapsedMilliseconds, // swMulAdd.ElapsedMilliseconds); if (negative) { eia = eia.Negate(); } // DebugUtility.Log("eia now="+eia); return(eia); } else { return(FromRadixSubstringInner(cs, radix, index, endIndex, negative)); } }
internal static EFloat DoubleEFloatFromString( string chars, int offset, int length, EContext ctx, bool throwException) { int tmpoffset = offset; if (chars == null) { if (!throwException) { return(null); } else { throw new ArgumentNullException(nameof(chars)); } } if (length == 0) { if (!throwException) { return(null); } else { throw new FormatException(); } } int endStr = tmpoffset + length; var negative = false; var haveDecimalPoint = false; var haveDigits = false; var haveExponent = false; var newScaleInt = 0; var digitStart = 0; int i = tmpoffset; long mantissaLong = 0L; // Ordinary number if (chars[i] == '+' || chars[i] == '-') { if (chars[i] == '-') { negative = true; } ++i; } digitStart = i; int digitEnd = i; int decimalDigitStart = i; var haveNonzeroDigit = false; var decimalPrec = 0; int decimalDigitEnd = i; var nonzeroBeyondMax = false; var lastdigit = -1; // 768 is maximum precision of a decimal // half-ULP in double format var maxDecimalPrec = 768; if (length > 21) { int eminInt = ctx.EMin.ToInt32Checked(); int emaxInt = ctx.EMax.ToInt32Checked(); int precInt = ctx.Precision.ToInt32Checked(); if (eminInt >= -14 && emaxInt <= 15) { maxDecimalPrec = (precInt <= 11) ? 21 : 63; } else if (eminInt >= -126 && emaxInt <= 127) { maxDecimalPrec = (precInt <= 24) ? 113 : 142; } } for (; i < endStr; ++i) { char ch = chars[i]; if (ch >= '0' && ch <= '9') { var thisdigit = (int)(ch - '0'); haveDigits = true; haveNonzeroDigit |= thisdigit != 0; if (decimalPrec > maxDecimalPrec) { if (thisdigit != 0) { nonzeroBeyondMax = true; } if (!haveDecimalPoint) { // NOTE: Absolute value will not be more than // the string portion's length, so will fit comfortably // in an 'int'. newScaleInt = checked (newScaleInt + 1); } continue; } lastdigit = thisdigit; if (haveNonzeroDigit) { ++decimalPrec; } if (haveDecimalPoint) { decimalDigitEnd = i + 1; } else { digitEnd = i + 1; } if (mantissaLong <= 922337203685477580L) { mantissaLong *= 10; mantissaLong += thisdigit; } else { mantissaLong = Int64.MaxValue; } if (haveDecimalPoint) { // NOTE: Absolute value will not be more than // the portion's length, so will fit comfortably // in an 'int'. newScaleInt = checked (newScaleInt - 1); } } else if (ch == '.') { if (haveDecimalPoint) { if (!throwException) { return(null); } else { throw new FormatException(); } } haveDecimalPoint = true; decimalDigitStart = i + 1; decimalDigitEnd = i + 1; } else if (ch == 'E' || ch == 'e') { haveExponent = true; ++i; break; } else { if (!throwException) { return(null); } else { throw new FormatException(); } } } if (!haveDigits) { if (!throwException) { return(null); } else { throw new FormatException(); } } var expInt = 0; var expoffset = 1; var expDigitStart = -1; var expPrec = 0; bool zeroMantissa = !haveNonzeroDigit; haveNonzeroDigit = false; EFloat ef1, ef2; if (haveExponent) { haveDigits = false; if (i == endStr) { if (!throwException) { return(null); } else { throw new FormatException(); } } char ch = chars[i]; if (ch == '+' || ch == '-') { if (ch == '-') { expoffset = -1; } ++i; } expDigitStart = i; for (; i < endStr; ++i) { ch = chars[i]; if (ch >= '0' && ch <= '9') { haveDigits = true; var thisdigit = (int)(ch - '0'); haveNonzeroDigit |= thisdigit != 0; if (haveNonzeroDigit) { ++expPrec; } if (expInt <= 214748364) { expInt *= 10; expInt += thisdigit; } else { expInt = Int32.MaxValue; } } else { if (!throwException) { return(null); } else { throw new FormatException(); } } } if (!haveDigits) { if (!throwException) { return(null); } else { throw new FormatException(); } } expInt *= expoffset; if (expPrec > 12) { // Exponent that can't be compensated by digit // length without remaining beyond Int32 range if (expoffset < 0) { return(EFloat.SignalUnderflow(ctx, negative, zeroMantissa)); } else { return(EFloat.SignalOverflow(ctx, negative, zeroMantissa)); } } } if (i != endStr) { if (!throwException) { return(null); } else { throw new FormatException(); } } if (expInt != Int32.MaxValue && expInt > -Int32.MaxValue && mantissaLong != Int64.MaxValue && (ctx == null || !ctx.HasFlagsOrTraps)) { if (mantissaLong == 0) { EFloat ef = EFloat.Create( EInteger.Zero, EInteger.FromInt32(expInt)); if (negative) { ef = ef.Negate(); } return(ef.RoundToPrecision(ctx)); } var finalexp = (long)expInt + (long)newScaleInt; long ml = mantissaLong; if (finalexp >= -22 && finalexp <= 44) { var iexp = (int)finalexp; while (ml <= 900719925474099L && iexp > 22) { ml *= 10; --iexp; } int iabsexp = Math.Abs(iexp); if (ml < 9007199254740992L && iabsexp == 0) { return(EFloat.FromInt64(negative ? -mantissaLong : mantissaLong).RoundToPrecision(ctx)); } else if (ml < 9007199254740992L && iabsexp <= 22) { EFloat efn = EFloat.FromEInteger(NumberUtility.FindPowerOfTen(iabsexp)); if (negative) { ml = -ml; } EFloat efml = EFloat.FromInt64(ml); if (iexp < 0) { return(efml.Divide(efn, ctx)); } else { return(efml.Multiply(efn, ctx)); } } } long adjexpUpperBound = finalexp + (decimalPrec - 1); long adjexpLowerBound = finalexp; if (adjexpUpperBound < -326) { return(EFloat.SignalUnderflow(ctx, negative, zeroMantissa)); } else if (adjexpLowerBound > 309) { return(EFloat.SignalOverflow(ctx, negative, zeroMantissa)); } if (negative) { mantissaLong = -mantissaLong; } long absfinalexp = Math.Abs(finalexp); ef1 = EFloat.Create(mantissaLong, (int)0); ef2 = EFloat.FromEInteger(NumberUtility.FindPowerOfTen(absfinalexp)); if (finalexp < 0) { EFloat efret = ef1.Divide(ef2, ctx); /* Console.WriteLine("div " + ef1 + "/" + ef2 + " -> " + (efret)); */return(efret); } else { return(ef1.Multiply(ef2, ctx)); } } EInteger mant = null; EInteger exp = (!haveExponent) ? EInteger.Zero : EInteger.FromSubstring(chars, expDigitStart, endStr); if (expoffset < 0) { exp = exp.Negate(); } exp = exp.Add(newScaleInt); if (nonzeroBeyondMax) { exp = exp.Subtract(1); ++decimalPrec; } EInteger adjExpUpperBound = exp.Add(decimalPrec).Subtract(1); EInteger adjExpLowerBound = exp; // DebugUtility.Log("exp=" + adjExpLowerBound + "~" + (adjExpUpperBound)); if (adjExpUpperBound.CompareTo(-326) < 0) { return(EFloat.SignalUnderflow(ctx, negative, zeroMantissa)); } else if (adjExpLowerBound.CompareTo(309) > 0) { return(EFloat.SignalOverflow(ctx, negative, zeroMantissa)); } if (zeroMantissa) { EFloat ef = EFloat.Create( EInteger.Zero, exp); if (negative) { ef = ef.Negate(); } return(ef.RoundToPrecision(ctx)); } else if (decimalDigitStart != decimalDigitEnd) { if (digitEnd - digitStart == 1 && chars[digitStart] == '0') { mant = EInteger.FromSubstring( chars, decimalDigitStart, decimalDigitEnd); } else { string ctmpstr = Extras.CharsConcat( chars, digitStart, digitEnd - digitStart, chars, decimalDigitStart, decimalDigitEnd - decimalDigitStart); mant = EInteger.FromString(ctmpstr); } } else { mant = EInteger.FromSubstring(chars, digitStart, digitEnd); } if (nonzeroBeyondMax) { mant = mant.Multiply(10).Add(1); } if (negative) { mant = mant.Negate(); } return(EDecimal.Create(mant, exp).ToEFloat(ctx)); }
private T PostProcessEx( T thisValue, EContext ctxDest, EContext ctxSrc, bool afterDivision, bool afterQuantize) { int thisFlags = this.GetHelper().GetFlags(thisValue); if (ctxDest != null && ctxSrc != null) { if (ctxDest.HasFlags) { if (!ctxSrc.ClampNormalExponents) { ctxSrc.Flags &= ~EContext.FlagClamped; } ctxDest.Flags |= ctxSrc.Flags; if ((ctxSrc.Flags & EContext.FlagSubnormal) != 0) { // Treat subnormal numbers as underflows ctxDest.Flags |= BigNumberFlags.UnderflowFlags; } } } if ((thisFlags & BigNumberFlags.FlagSpecial) != 0) { return((ctxDest.Flags == 0) ? this.SignalInvalid(ctxDest) : thisValue); } EInteger mant = this.GetHelper().GetMantissa(thisValue).Abs(); if (mant.IsZero) { return(afterQuantize ? this.GetHelper().CreateNewWithFlags( mant, this.GetHelper().GetExponent(thisValue), 0) : this.wrapper.RoundToPrecision( this.GetHelper().ValueOf(0), ctxDest)); } if (afterQuantize) { return(thisValue); } EInteger exp = this.GetHelper().GetExponent(thisValue); if (exp.Sign > 0) { FastInteger fastExp = FastInteger.FromBig(exp); if (ctxDest == null || !ctxDest.HasMaxPrecision) { mant = this.GetHelper().MultiplyByRadixPower(mant, fastExp); return(this.GetHelper().CreateNewWithFlags( mant, EInteger.Zero, thisFlags)); } if (!ctxDest.ExponentWithinRange(exp)) { return(thisValue); } FastInteger prec = FastInteger.FromBig(ctxDest.Precision); FastInteger digits = this.GetHelper().CreateShiftAccumulator(mant).GetDigitLength(); prec.Subtract(digits); if (prec.Sign > 0 && prec.CompareTo(fastExp) >= 0) { mant = this.GetHelper().MultiplyByRadixPower(mant, fastExp); return(this.GetHelper().CreateNewWithFlags( mant, EInteger.Zero, thisFlags)); } if (afterDivision) { int radix = this.GetHelper().GetRadix(); mant = NumberUtility.ReduceTrailingZeros( mant, fastExp, radix, null, null, null); thisValue = this.GetHelper().CreateNewWithFlags( mant, fastExp.AsEInteger(), thisFlags); } } else if (afterDivision && exp.Sign < 0) { FastInteger fastExp = FastInteger.FromBig(exp); int radix = this.GetHelper().GetRadix(); mant = NumberUtility.ReduceTrailingZeros( mant, fastExp, radix, null, null, new FastInteger(0)); thisValue = this.GetHelper().CreateNewWithFlags( mant, fastExp.AsEInteger(), thisFlags); } return(thisValue); }
private T PreRound(T val, EContext ctx) { return(NumberUtility.PreRound(val, ctx, this.wrapper)); }
private void ShiftToDigitsBig(int digits, bool truncate) { // Shifts a number until it reaches the given number of digits, // gathering information on whether the last digit discarded is set // and whether the discarded digits to the right of that digit are set. // Assumes that the big integer being shifted is positive. if (this.knownDigitLength != null) { if (this.knownDigitLength.CompareToInt(digits) <= 0) { return; } } string str; this.knownDigitLength = this.knownDigitLength ?? this.CalcKnownDigitLength(); if (this.knownDigitLength.CompareToInt(digits) <= 0) { return; } FastInteger digitDiff = this.knownDigitLength.Copy().SubtractInt(digits); if (truncate && digitDiff.CanFitInInt32()) { this.TruncateRight(digitDiff); return; } if (digitDiff.CompareToInt(1) == 0) { EInteger bigrem; EInteger bigquo; EInteger[] divrem = this.shiftedBigInt.DivRem(ValueTen); bigquo = divrem[0]; bigrem = divrem[1]; this.bitsAfterLeftmost |= this.bitLeftmost; this.bitLeftmost = (int)bigrem; this.shiftedBigInt = bigquo; this.discardedBitCount = this.discardedBitCount ?? (new FastInteger(0)); this.discardedBitCount.Add(digitDiff); this.UpdateKnownLength(digitDiff); this.bitsAfterLeftmost = (this.bitsAfterLeftmost != 0) ? 1 : 0; return; } if (digitDiff.CompareToInt(9) <= 0) { EInteger bigrem; int diffInt = digitDiff.AsInt32(); EInteger radixPower = NumberUtility.FindPowerOfTen(diffInt); EInteger bigquo; EInteger[] divrem = this.shiftedBigInt.DivRem(radixPower); bigquo = divrem[0]; bigrem = divrem[1]; var rem = (int)bigrem; this.bitsAfterLeftmost |= this.bitLeftmost; for (var i = 0; i < diffInt; ++i) { if (i == diffInt - 1) { this.bitLeftmost = rem % 10; } else { int intQuot = (rem < 43698) ? ((rem * 26215) >> 18) : (rem / 10); this.bitsAfterLeftmost |= rem - (intQuot * 10); rem = intQuot; } } this.shiftedBigInt = bigquo; this.discardedBitCount = this.discardedBitCount ?? (new FastInteger(0)); this.discardedBitCount.Add(digitDiff); this.UpdateKnownLength(digitDiff); this.bitsAfterLeftmost = (this.bitsAfterLeftmost != 0) ? 1 : 0; return; } if (digitDiff.CanFitInInt32()) { #if DEBUG if (!(digitDiff.CompareToInt(2) > 0)) { throw new ArgumentException( "doesn't satisfy digitDiff.CompareToInt(2)>0"); } #endif EInteger bigrem = null; EInteger bigquo; EInteger[] divrem; if (!this.shiftedBigInt.IsEven || this.bitsAfterLeftmost != 0) { EInteger radixPower = NumberUtility.FindPowerOfTen(digitDiff.AsInt32() - 1); this.bitsAfterLeftmost |= 1; bigquo = this.shiftedBigInt.Divide(radixPower); } else { EInteger radixPower = NumberUtility.FindPowerOfTen(digitDiff.AsInt32() - 1); divrem = this.shiftedBigInt.DivRem(radixPower); bigquo = divrem[0]; bigrem = divrem[1]; this.bitsAfterLeftmost |= this.bitLeftmost; if (!bigrem.IsZero) { this.bitsAfterLeftmost |= 1; } } EInteger bigquo2; divrem = bigquo.DivRem(ValueTen); bigquo2 = divrem[0]; bigrem = divrem[1]; this.bitLeftmost = (int)bigrem; this.shiftedBigInt = bigquo2; this.discardedBitCount = this.discardedBitCount ?? (new FastInteger(0)); this.discardedBitCount.Add(digitDiff); this.UpdateKnownLength(digitDiff); this.bitsAfterLeftmost = (this.bitsAfterLeftmost != 0) ? 1 : 0; return; } str = this.shiftedBigInt.ToString(); // NOTE: Will be 1 if the value is 0 int digitLength = str.Length; this.knownDigitLength = new FastInteger(digitLength); // Shift by the difference in digit length if (digitLength > digits) { int digitShift = digitLength - digits; this.UpdateKnownLengthInt(digitShift); var newLength = (int)(digitLength - digitShift); // Console.WriteLine("dlen= " + digitLength + " dshift=" + // digitShift + " newlen= " + newLength); this.discardedBitCount = this.discardedBitCount ?? (new FastInteger(0)); if (digitShift <= Int32.MaxValue) { this.discardedBitCount.AddInt((int)digitShift); } else { this.discardedBitCount.AddBig((EInteger)digitShift); } for (int i = str.Length - 1; i >= 0; --i) { this.bitsAfterLeftmost |= this.bitLeftmost; this.bitLeftmost = (int)(str[i] - '0'); --digitShift; if (digitShift <= 0) { break; } } if (newLength <= 9) { this.isSmall = true; this.shiftedSmall = FastParseLong(str, 0, newLength); } else { this.shiftedBigInt = EInteger.FromSubstring(str, 0, newLength); } this.bitsAfterLeftmost = (this.bitsAfterLeftmost != 0) ? 1 : 0; } }
private void ShiftRightBig(int digits, bool truncate) { if (digits <= 0) { return; } if (this.shiftedBigInt.IsZero) { this.discardedBitCount = this.discardedBitCount ?? (new FastInteger(0)); this.discardedBitCount.AddInt(digits); this.bitsAfterLeftmost |= this.bitLeftmost; this.bitLeftmost = 0; this.knownDigitLength = new FastInteger(1); return; } if (truncate) { EInteger bigquo; if (digits > 50) { // To avoid having to calculate a very big power of 10, // check the digit count to see if doing so can be avoided int bitLength = this.shiftedBigInt.GetUnsignedBitLength(); var bigPower = false; // 10^48 has 160 bits; 10^98 has 326; bit length is cheaper // to calculate than base-10 digit length if (bitLength < 160 || (digits > 100 && bitLength < 326)) { bigPower = true; } else { FastInteger knownDigits = this.GetDigitLength(); bigPower = knownDigits.Copy().SubtractInt(digits) .CompareToInt(-2) < 0; if (!bigPower) { // DebugUtility.Log("digitlength {0} [todiscard: {1}]" // , knownDigits, digits); } } if (bigPower) { // Power of 10 to be divided would be much bigger this.discardedBitCount = this.discardedBitCount ?? (new FastInteger(0)); this.discardedBitCount.AddInt(digits); this.bitsAfterLeftmost |= this.bitLeftmost; this.bitsAfterLeftmost |= this.shiftedBigInt.IsZero ? 0 : 1; this.bitLeftmost = 0; this.knownDigitLength = new FastInteger(1); this.isSmall = true; this.shiftedSmall = 0; return; } } if (this.shiftedBigInt.IsEven && this.bitLeftmost == 0) { EInteger[] quorem = this.shiftedBigInt.DivRem( NumberUtility.FindPowerOfTen(digits)); bigquo = quorem[0]; this.bitLeftmost |= quorem[1].IsZero ? 0 : 1; } else { this.bitLeftmost = 1; bigquo = this.shiftedBigInt.Divide( NumberUtility.FindPowerOfTen(digits)); } this.bitsAfterLeftmost |= this.bitLeftmost; this.discardedBitCount = this.discardedBitCount == null ? new FastInteger(digits) : this.discardedBitCount.AddInt(digits); if (bigquo.IsZero) { // Shifted all the way to 0 this.isSmall = true; this.shiftedBigInt = null; this.shiftedSmall = 0; this.knownDigitLength = new FastInteger(1); } else if (bigquo.CanFitInInt32()) { this.isSmall = true; this.shiftedSmall = bigquo.ToInt32Unchecked(); this.shiftedBigInt = null; this.UpdateKnownLengthInt(digits); } else { this.isSmall = false; this.shiftedBigInt = bigquo; this.UpdateKnownLengthInt(digits); } return; } if (digits == 1) { EInteger bigrem; EInteger bigquo; EInteger[] divrem = this.shiftedBigInt.DivRem((EInteger)10); bigquo = divrem[0]; bigrem = divrem[1]; this.bitsAfterLeftmost |= this.bitLeftmost; this.bitLeftmost = (int)bigrem; this.shiftedBigInt = bigquo; this.discardedBitCount = this.discardedBitCount ?? (new FastInteger(0)); this.discardedBitCount.AddInt(digits); this.UpdateKnownLengthInt(digits); return; } if (digits >= 2 && digits <= 8) { EInteger bigrem; EInteger bigquo; EInteger[] divrem = this.shiftedBigInt.DivRem(NumberUtility.FindPowerOfTen(digits)); bigquo = divrem[0]; bigrem = divrem[1]; var intRem = (int)bigrem; int smallPower = ValueTenPowers[digits - 1]; int leftBit = intRem / smallPower; int otherBits = intRem - (leftBit * smallPower); this.bitsAfterLeftmost |= otherBits | this.bitLeftmost; this.bitLeftmost = leftBit; this.shiftedBigInt = bigquo; this.discardedBitCount = (this.discardedBitCount != null) ? this.discardedBitCount.AddInt(digits) : (new FastInteger(digits)); this.UpdateKnownLengthInt(digits); this.bitsAfterLeftmost = (this.bitsAfterLeftmost != 0) ? 1 : 0; if (this.shiftedBigInt.CanFitInInt32()) { this.isSmall = true; this.shiftedSmall = this.shiftedBigInt.ToInt32Unchecked(); this.shiftedBigInt = null; } return; } this.knownDigitLength = this.knownDigitLength ?? this.CalcKnownDigitLength(); if (new FastInteger(digits).Decrement().CompareTo(this.knownDigitLength) >= 0) { // Shifting more bits than available this.bitsAfterLeftmost |= this.shiftedBigInt.IsZero ? 0 : 1; this.isSmall = true; this.shiftedSmall = 0; this.knownDigitLength = new FastInteger(1); this.discardedBitCount = this.discardedBitCount ?? (new FastInteger(0)); this.discardedBitCount.AddInt(digits); this.bitsAfterLeftmost |= this.bitLeftmost; this.bitLeftmost = 0; return; } if (this.shiftedBigInt.CanFitInInt32()) { this.isSmall = true; this.shiftedSmall = (int)this.shiftedBigInt; this.ShiftRightSmall(digits); return; } if (this.shiftedBigInt.CanFitInInt64()) { this.ShiftRightLong(this.shiftedBigInt.ToInt64Unchecked(), digits); return; } string str = this.shiftedBigInt.ToString(); // NOTE: Will be 1 if the value is 0 int digitLength = str.Length; var bitDiff = 0; if (digits > digitLength) { bitDiff = digits - digitLength; } this.discardedBitCount = this.discardedBitCount ?? (new FastInteger(0)); this.discardedBitCount.AddInt(digits); this.bitsAfterLeftmost |= this.bitLeftmost; int digitShift = Math.Min(digitLength, digits); if (digits >= digitLength) { this.isSmall = true; this.shiftedSmall = 0; this.knownDigitLength = new FastInteger(1); } else { var newLength = (int)(digitLength - digitShift); if (newLength <= 9) { // Fits in a small number this.isSmall = true; this.shiftedSmall = FastParseLong(str, 0, newLength); } else { this.shiftedBigInt = EInteger.FromSubstring(str, 0, newLength); } this.UpdateKnownLengthInt(digitShift); } for (int i = str.Length - 1; i >= 0; --i) { this.bitsAfterLeftmost |= this.bitLeftmost; this.bitLeftmost = (int)(str[i] - '0'); --digitShift; if (digitShift <= 0) { break; } } this.bitsAfterLeftmost = (this.bitsAfterLeftmost != 0) ? 1 : 0; if (bitDiff > 0) { // Shifted more digits than the digit length this.bitsAfterLeftmost |= this.bitLeftmost; this.bitLeftmost = 0; } }
public static THelper PreRound <THelper>( THelper val, EContext ctx, IRadixMath <THelper> wrapper) { if (ctx == null || !ctx.HasMaxPrecision) { return(val); } IRadixMathHelper <THelper> helper = wrapper.GetHelper(); int thisFlags = helper.GetFlags(val); if ((thisFlags & BigNumberFlags.FlagSpecial) != 0) { // Infinity or NaN return(val); } FastInteger fastPrecision = FastInteger.FromBig(ctx.Precision); EInteger mant = helper.GetMantissa(val).Abs(); // Rounding is only to be done if the digit count is // too big (distinguishing this case is material // if the value also has an exponent that's out of range) FastInteger[] digitBounds = NumberUtility.DigitLengthBounds( helper, mant); if (digitBounds[1].CompareTo(fastPrecision) <= 0) { // Upper bound is less than or equal to precision return(val); } EContext ctx2 = ctx; if (digitBounds[0].CompareTo(fastPrecision) <= 0) { // Lower bound is less than or equal to precision, so // calculate digit length more precisely FastInteger digits = helper.GetDigitLength(mant); ctx2 = ctx.WithBlankFlags().WithTraps(0); if (digits.CompareTo(fastPrecision) <= 0) { return(val); } } val = wrapper.RoundToPrecision(val, ctx2); // the only time rounding can signal an invalid // operation is if an operand is a signaling NaN, but // this was already checked beforehand #if DEBUG if ((ctx2.Flags & EContext.FlagInvalid) != 0) { throw new ArgumentException("doesn't" + "\u0020satisfy(ctx2.Flags&FlagInvalid)==0"); } #endif if ((ctx2.Flags & EContext.FlagInexact) != 0) { if (ctx.HasFlags) { ctx.Flags |= BigNumberFlags.LostDigitsFlags; } } if ((ctx2.Flags & EContext.FlagRounded) != 0) { if (ctx.HasFlags) { ctx.Flags |= EContext.FlagRounded; } } if ((ctx2.Flags & EContext.FlagOverflow) != 0) { bool neg = (thisFlags & BigNumberFlags.FlagNegative) != 0; if (ctx.HasFlags) { ctx.Flags |= EContext.FlagLostDigits; ctx.Flags |= EContext.FlagOverflow | EContext.FlagInexact | EContext.FlagRounded; } } return(val); }