public T Quantize(T thisValue, T otherValue, EContext ctx) { T ret = this.CheckNotANumber1(thisValue, ctx); if ((object)ret != (object)default(T)) { return(ret); } EContext ctx2 = GetContextWithFlags(ctx); // Console.WriteLine("was: "+thisValue+", "+otherValue); thisValue = this.RoundBeforeOp(thisValue, ctx2); // Console.WriteLine("now: "+thisValue+", "+otherValue); otherValue = this.RoundBeforeOp(otherValue, ctx2); // Apparently, subnormal values of "otherValue" raise // an invalid operation flag, according to the test cases EContext ctx3 = ctx2 == null ? null : ctx2.WithBlankFlags(); this.wrapper.RoundToPrecision(otherValue, ctx3); if (ctx3 != null && (ctx3.Flags & EContext.FlagSubnormal) != 0) { return(this.SignalInvalid(ctx)); } thisValue = this.wrapper.Quantize(thisValue, otherValue, ctx2); // Console.WriteLine("result: "+thisValue); return(this.PostProcessAfterQuantize(thisValue, ctx, ctx2)); }
private static EContext GetTrappableContext(EContext ctx) { return((ctx == null) ? null : ((ctx.Traps == 0) ? ctx : ctx.WithBlankFlags())); }
private static EContext GetContextWithFlags(EContext ctx) { return((ctx == null) ? ctx : ctx.WithBlankFlags()); }
private T RoundBeforeOp(T val, EContext ctx) { if (ctx == null || !ctx.HasMaxPrecision) { return(val); } int thisFlags = this.GetHelper().GetFlags(val); if ((thisFlags & BigNumberFlags.FlagSpecial) != 0) { return(val); } FastInteger fastPrecision = FastInteger.FromBig(ctx.Precision); EInteger mant = this.GetHelper().GetMantissa(val).Abs(); FastInteger digits = this.GetHelper().CreateShiftAccumulator(mant).GetDigitLength(); EContext ctx2 = ctx.WithBlankFlags().WithTraps(0); if (digits.CompareTo(fastPrecision) <= 0) { // 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) return(val); } val = this.wrapper.RoundToPrecision(val, ctx2); // the only time rounding can signal an invalid // operation is if an operand is signaling NaN, but // this was already checked beforehand #if DEBUG if ((ctx2.Flags & EContext.FlagInvalid) != 0) { throw new ArgumentException("doesn't satisfy (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.FlagSubnormal) != 0) { // Console.WriteLine("Subnormal input: " + val); } if ((ctx2.Flags & EContext.FlagUnderflow) != 0) { // Console.WriteLine("Underflow"); } if ((ctx2.Flags & EContext.FlagOverflow) != 0) { bool neg = (thisFlags & BigNumberFlags.FlagNegative) != 0; ctx.Flags |= EContext.FlagLostDigits; return(this.SignalOverflow2(ctx, neg)); } return(val); }
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); }