예제 #1
0
 /// <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;
 }
예제 #2
0
 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;
 }
예제 #3
0
 /// <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);
   }
 }
예제 #4
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;
 }
예제 #5
0
        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;
            }
        }
예제 #6
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));
        }
예제 #7
0
 /// <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)));
 }
예제 #8
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;
     }
 }