Esempio n. 1
0
 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));
     }
 }
Esempio n. 2
0
        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));
        }
Esempio n. 3
0
        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);
        }
Esempio n. 4
0
 private T PreRound(T val, EContext ctx)
 {
     return(NumberUtility.PreRound(val, ctx, this.wrapper));
 }
Esempio n. 5
0
        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;
            }
        }
Esempio n. 6
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;
            }
        }
Esempio n. 7
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);
        }