/// <include file='../../docs.xml' /// path='docs/doc[@name="M:PeterO.Numbers.EContext.WithBigExponentRange(PeterO.Numbers.EInteger,PeterO.Numbers.EInteger)"]/*'/> public EContext WithBigExponentRange( EInteger exponentMin, EInteger exponentMax) { if (exponentMin == null) { throw new ArgumentNullException("exponentMin"); } if (exponentMax == null) { throw new ArgumentNullException("exponentMax"); } if (exponentMin.CompareTo(exponentMax) > 0) { throw new ArgumentException("exponentMin greater than exponentMax"); } EContext pc = this.Copy(); pc.hasExponentRange = true; pc.exponentMin = exponentMin; pc.exponentMax = exponentMax; return pc; }
internal static EInteger FindPowerOfTenFromBig(EInteger bigintExponent) { int sign = bigintExponent.Sign; if (sign < 0) { return EInteger.Zero; } if (sign == 0) { return EInteger.One; } if (bigintExponent.CompareTo(ValueBigInt36) <= 0) { return FindPowerOfTen((int)bigintExponent); } FastInteger intcurexp = FastInteger.FromBig(bigintExponent); EInteger mantissa = EInteger.One; EInteger bigpow = EInteger.Zero; while (intcurexp.Sign > 0) { if (intcurexp.CompareToInt(18) <= 0) { bigpow = FindPowerOfTen(intcurexp.AsInt32()); mantissa *= (EInteger)bigpow; break; } if (intcurexp.CompareToInt(9999999) <= 0) { int val = intcurexp.AsInt32(); bigpow = FindPowerOfFive(val); bigpow <<= val; mantissa *= (EInteger)bigpow; break; } if (bigpow.IsZero) { bigpow = FindPowerOfFive(9999999); bigpow <<= 9999999; } mantissa *= bigpow; intcurexp.AddInt(-9999999); } return mantissa; }
/// <include file='../../docs.xml' /// path='docs/doc[@name="M:PeterO.Numbers.EContext.ExponentWithinRange(PeterO.Numbers.EInteger)"]/*'/> public bool ExponentWithinRange(EInteger exponent) { if (exponent == null) { throw new ArgumentNullException("exponent"); } if (!this.HasExponentRange) { return true; } if (this.bigintPrecision.IsZero) { // Only check EMax, since with an unlimited // precision, any exponent less than EMin will exceed EMin if // the mantissa is the right size return exponent.CompareTo(this.EMax) <= 0; } else { EInteger bigint = exponent; if (this.adjustExponent) { bigint += (EInteger)this.bigintPrecision; bigint -= EInteger.One; } return (bigint.CompareTo(this.EMin) >= 0) && (exponent.CompareTo(this.EMax) <= 0); } }
internal static EInteger ShiftLeft(EInteger val, EInteger bigShift) { #if DEBUG if (val == null) { throw new ArgumentNullException("val"); } if (bigShift == null) { throw new ArgumentNullException("bigShift"); } #endif if (val.IsZero) { return val; } while (bigShift.CompareTo(ValueBigShiftIteration) > 0) { val <<= 1000000; bigShift -= (EInteger)ValueBigShiftIteration; } var lastshift = (int)bigShift; val <<= lastshift; return val; }
private void ShiftRightBig(int bits) { if (bits <= 0) { return; } if (this.shiftedBigInt.IsZero) { this.discardedBitCount.AddInt(bits); this.bitsAfterLeftmost |= this.bitLeftmost; this.bitLeftmost = 0; this.isSmall = true; this.shiftedSmall = 0; this.knownBitLength = new FastInteger(1); return; } this.knownBitLength = this.knownBitLength ?? this.CalcKnownBitLength(); this.discardedBitCount.AddInt(bits); int cmp = this.knownBitLength.CompareToInt(bits); if (cmp < 0) { // too few bits this.bitsAfterLeftmost |= this.bitLeftmost; this.bitsAfterLeftmost |= this.shiftedBigInt.IsZero ? 0 : 1; this.bitLeftmost = 0; this.isSmall = true; this.shiftedSmall = 0; this.knownBitLength = new FastInteger(1); } else { // enough bits in the current value int bs = bits; this.knownBitLength.SubtractInt(bits); if (bs == 1) { bool odd = !this.shiftedBigInt.IsEven; this.shiftedBigInt >>= 1; this.bitsAfterLeftmost |= this.bitLeftmost; this.bitLeftmost = odd ? 1 : 0; } else { this.bitsAfterLeftmost |= this.bitLeftmost; long lowestSet = this.shiftedBigInt.GetLowBitAsInt64(); if (lowestSet == Int64.MaxValue) { EInteger lowestSetBit = this.shiftedBigInt.GetLowBitAsEInteger(); if (lowestSetBit.CompareTo(bs - 1) < 0) { // One of the discarded bits after // the last one is set this.bitsAfterLeftmost |= 1; this.bitLeftmost = this.shiftedBigInt.GetSignedBit(bs - 1) ? 1 : 0; } else if (lowestSetBit.CompareTo(bs - 1) > 0) { // Means all discarded bits are zero this.bitLeftmost = 0; } else { // Only the last discarded bit is set this.bitLeftmost = 1; } } else { if (lowestSet < bs - 1) { // One of the discarded bits after // the last one is set this.bitsAfterLeftmost |= 1; this.bitLeftmost = this.shiftedBigInt.GetSignedBit(bs - 1) ? 1 : 0; } else if (lowestSet > bs - 1) { // Means all discarded bits are zero this.bitLeftmost = 0; } else { // Only the last discarded bit is set this.bitLeftmost = 1; } } this.shiftedBigInt >>= bs; } if (this.knownBitLength.CompareToInt(SmallBitLength) < 0) { // Shifting to small number of bits, // convert to small integer this.isSmall = true; this.shiftedSmall = (int)this.shiftedBigInt; } this.bitsAfterLeftmost = (this.bitsAfterLeftmost != 0) ? 1 : 0; } }
internal static EFloat DoubleEFloatFromString( string chars, int offset, int length, EContext ctx) { int tmpoffset = offset; if (chars == null) { throw new ArgumentNullException(nameof(chars)); } if (length == 0) { 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) { throw new FormatException(); } haveDecimalPoint = true; decimalDigitStart = i + 1; decimalDigitEnd = i + 1; } else if (ch == 'E' || ch == 'e') { haveExponent = true; ++i; break; } else { throw new FormatException(); } } if (!haveDigits) { 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) { 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 { throw new FormatException(); } } if (!haveDigits) { 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) { 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)); }
/// <include file='../../docs.xml' /// path='docs/doc[@name="M:PeterO.Cbor.CBORTypeFilter.ArrayLengthMatches(PeterO.Numbers.EInteger)"]/*'/> public bool ArrayLengthMatches(EInteger bigLength) { if (bigLength == null) { throw new ArgumentNullException("bigLength"); } return ((this.types & (1 << 4)) == 0) && (this.anyArrayLength || ((!this.arrayMinLength && bigLength.CompareTo((EInteger)this.arrayLength) == 0) || (this.arrayMinLength && bigLength.CompareTo((EInteger)this.arrayLength) >= 0))); }
private void ShiftBigToBits(int bits) { // Shifts a number until it reaches the given number of bits, // gathering information on whether the last bit discarded is set and // whether the discarded bits to the right of that bit are set. Assumes // that the big integer being shifted is positive. if (this.knownBitLength != null) { if (this.knownBitLength.CompareToInt(bits) <= 0) { return; } } this.knownBitLength = this.knownBitLength ?? this.CalcKnownBitLength(); if (this.knownBitLength.CompareToInt(bits) <= 0) { return; } // Shift by the difference in bit length if (this.knownBitLength.CompareToInt(bits) > 0) { var bs = 0; if (this.knownBitLength.CanFitInInt32()) { bs = this.knownBitLength.AsInt32(); bs -= bits; } else { FastInteger bitShift = this.knownBitLength.Copy().SubtractInt(bits); if (!bitShift.CanFitInInt32()) { this.ShiftRight(bitShift); return; } bs = bitShift.AsInt32(); } this.knownBitLength.SetInt(bits); this.discardedBitCount.AddInt(bs); if (bs == 1) { bool odd = !this.shiftedBigInt.IsEven; this.shiftedBigInt >>= 1; this.bitsAfterLeftmost |= this.bitLeftmost; this.bitLeftmost = odd ? 1 : 0; } else { this.bitsAfterLeftmost |= this.bitLeftmost; EInteger lowestSetBit = this.shiftedBigInt.GetLowBitAsEInteger(); if (lowestSetBit.CompareTo(bs - 1) < 0) { // One of the discarded bits after // the last one is set this.bitsAfterLeftmost |= 1; this.bitLeftmost = this.shiftedBigInt.GetSignedBit(bs - 1) ? 1 : 0; } else if (lowestSetBit.CompareTo(bs - 1) > 0) { // Means all discarded bits are zero this.bitLeftmost = 0; } else { // Only the last discarded bit is set this.bitLeftmost = 1; } this.shiftedBigInt >>= bs; } if (bits < SmallBitLength) { // Shifting to small number of bits, // convert to small integer this.isSmall = true; this.shiftedSmall = (int)this.shiftedBigInt; } this.bitsAfterLeftmost = (this.bitsAfterLeftmost != 0) ? 1 : 0; } }