private T ReturnQuietNaN(T thisValue, EContext ctx) { EInteger mant = this.GetHelper().GetMantissa(thisValue).Abs(); var mantChanged = false; if (!mant.IsZero && ctx != null && ctx.HasMaxPrecision) { EInteger limit = this.GetHelper().MultiplyByRadixPower( EInteger.One, FastInteger.FromBig(ctx.Precision)); if (mant.CompareTo(limit) >= 0) { mant %= (EInteger)limit; mantChanged = true; } } int flags = this.GetHelper().GetFlags(thisValue); if (!mantChanged && (flags & BigNumberFlags.FlagQuietNaN) != 0) { return(thisValue); } flags &= BigNumberFlags.FlagNegative; flags |= BigNumberFlags.FlagQuietNaN; return(this.GetHelper().CreateNewWithFlags(mant, EInteger.Zero, flags)); }
private FastInteger CalcKnownBitLength() { if (this.isSmall) { int kb = SmallBitLength; for (int i = SmallBitLength - 1; i >= 0; --i) { if ((this.shiftedSmall & (1 << i)) != 0) { break; } --kb; } // Make sure bit length is 1 if value is 0 if (kb == 0) { ++kb; } return(new FastInteger(kb)); } if (this.shiftedBigInt.IsZero) { { return(new FastInteger(1)); } } long sbe = this.shiftedBigInt.GetSignedBitLengthAsInt64(); return((sbe < Int32.MaxValue) ? new FastInteger((int)sbe) : FastInteger.FromBig(this.shiftedBigInt.GetSignedBitLengthAsEInteger())); }
public FastInteger ToFastInteger() { if (this.integerMode == IntegerMode.SmallValue) { return(new FastInteger(this.smallValue)); } else { return(FastInteger.FromBig(this.largeValue)); } }
public static FastInteger[] DigitLengthBounds <THelper>( IRadixMathHelper <THelper> helper, EInteger ei) { int radix = helper.GetRadix(); if (radix == 2) { FastInteger fi = FastInteger.FromBig(ei.GetUnsignedBitLengthAsEInteger()); return(new FastInteger[] { fi, fi }); } else if (radix == 10) { return(DecimalDigitLengthBounds(ei)); } else { FastInteger fi = helper.GetDigitLength(ei); return(new FastInteger[] { fi, fi }); } }
public void ShiftToDigits( FastInteger bits, FastInteger preShift, bool truncate) { if (bits.Sign < 0) { throw new ArgumentException("bits's sign(" + bits.Sign + ") is less than 0"); } if (preShift != null && preShift.Sign > 0) { this.knownBitLength = this.knownBitLength ?? this.CalcKnownBitLength(); // DebugUtility.Log("bits=" + bits + " pre=" + preShift + " known=" + // (//kbl) + " [" + this.shiftedBigInt + "]"); if (this.knownBitLength.CompareTo(bits) <= 0) { // Known digit length is already small enough // NOTE: For BitShiftAccumulator, truncating and shifting // are the same, unlike in DigitShiftAccumulator this.ShiftRight(preShift); VerifyKnownLength(); return; } else { FastInteger bitDiff = this.knownBitLength.Copy() .Subtract(bits); // DebugUtility.Log("bitDiff=" + bitDiff); int cmp = bitDiff.CompareTo(preShift); if (cmp <= 0) { // NOTE: For BitShiftAccumulator, truncating and shifting // are the same, unlike in DigitShiftAccumulator this.ShiftRight(preShift); VerifyKnownLength(); return; } else { // NOTE: For BitShiftAccumulator, truncating and shifting // are the same, unlike in DigitShiftAccumulator this.ShiftRight(bitDiff); VerifyKnownLength(); return; } } } if (bits.CanFitInInt32()) { this.ShiftToDigitsInt(bits.ToInt32()); VerifyKnownLength(); } else { this.knownBitLength = this.knownBitLength ?? this.CalcKnownBitLength(); EInteger bigintDiff = this.knownBitLength.ToEInteger(); EInteger bitsBig = bits.ToEInteger(); bigintDiff -= (EInteger)bitsBig; if (bigintDiff.Sign > 0) { // current length is greater than the // desired bit length this.ShiftRight(FastInteger.FromBig(bigintDiff)); } VerifyKnownLength(); } }
public static FastInteger[] DecimalDigitLengthBounds(EInteger ei) { long longBitLength = ei.GetUnsignedBitLengthAsInt64(); if (longBitLength < 33) { // Can easily be calculated without estimation var fi = new FastInteger((int)ei.GetDigitCountAsInt64()); return(new FastInteger[] { fi, fi }); } else if (longBitLength <= 2135) { var bitlen = (int)longBitLength; int minDigits = 1 + (((bitlen - 1) * 631305) >> 21); int maxDigits = 1 + ((bitlen * 631305) >> 21); if (minDigits == maxDigits) { var fi = new FastInteger(minDigits); return(new FastInteger[] { fi, fi }); } else { return(new FastInteger[] { new FastInteger(minDigits), // lower bound new FastInteger(maxDigits), // upper bound }); } } else if (longBitLength <= 6432162) { var bitlen = (int)longBitLength; // Approximation of ln(2)/ln(10) int minDigits = 1 + (int)(((long)(bitlen - 1) * 661971961083L) >> 41); int maxDigits = 1 + (int)(((long)bitlen * 661971961083L) >> 41); if (minDigits == maxDigits) { var fi = new FastInteger(minDigits); return(new FastInteger[] { fi, fi }); } else { return(new FastInteger[] { new FastInteger(minDigits), // lower bound new FastInteger(maxDigits), // upper bound }); } } else { // Bit length is big enough that these bounds will // overestimate or underestimate the true base-10 digit length // as appropriate. EInteger bigBitLength = ei.GetUnsignedBitLengthAsEInteger(); EInteger lowerBound = bigBitLength.Multiply(100).Divide(335); EInteger upperBound = bigBitLength.Divide(3); return(new FastInteger[] { FastInteger.FromBig(lowerBound), // lower bound FastInteger.FromBig(upperBound), // upper bound }); } }
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); }
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 |= EContext.FlagUnderflow | EContext.FlagSubnormal | EContext.FlagInexact | EContext.FlagRounded; } } } 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().GetDigitLength(mant); 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.ToEInteger(), 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.ToEInteger(), thisFlags); } return(thisValue); }