Beispiel #1
0
        /// <summary>
        /// Division (this = this / n2)
        /// </summary>
        /// <param name="n2">The number to divide this by</param>
        public void Div(BigFloat n2)
        {
            if (SpecialValueDivTest(n2)) return;

            if (mantissa.Precision.NumBits >= 8192)
            {
                BigFloat rcp = n2.Reciprocal();
                Mul(rcp);
            }
            else
            {
                int shift = mantissa.DivAndShift(n2.mantissa);
                exponent = exponent - (n2.exponent + shift);
            }
        }
Beispiel #2
0
        /// <summary>
        /// Calculates the odd reciprocals of the natural numbers (for atan series)
        /// </summary>
        /// <param name="numBits"></param>
        /// <param name="terms"></param>
        private static void CalculateReciprocals(int numBits, int terms)
        {
            int bits = numBits + 32;
            PrecisionSpec extendedPres = new PrecisionSpec(bits, PrecisionSpec.BaseType.BIN);
            PrecisionSpec normalPres = new PrecisionSpec(numBits, PrecisionSpec.BaseType.BIN);

            System.Collections.Generic.List<BigFloat> list = new System.Collections.Generic.List<BigFloat>(terms);

            for (int i = 0; i < terms; i++)
            {
                BigFloat term = new BigFloat(i*2 + 1, extendedPres);
                list.Add(new BigFloat(term.Reciprocal(), normalPres));
            }

            reciprocals = list.ToArray();
        }
Beispiel #3
0
        /// <summary>
        /// Constructs a BigFloat from a string
        /// </summary>
        /// <param name="value"></param>
        /// <param name="mantissaPrec"></param>
        public BigFloat(string value, PrecisionSpec mantissaPrec)
        {
            Init(mantissaPrec);

            PrecisionSpec extendedPres = new PrecisionSpec(mantissa.Precision.NumBits + 1, PrecisionSpec.BaseType.BIN);
            BigFloat ten = new BigFloat(10, extendedPres);
            BigFloat iPart = new BigFloat(extendedPres);
            BigFloat fPart = new BigFloat(extendedPres);
            BigFloat tenRCP = ten.Reciprocal();

            if (value.Contains(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NaNSymbol))
            {
                SetNaN();
                return;
            }
            else if (value.Contains(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PositiveInfinitySymbol))
            {
                SetInfPlus();
                return;
            }
            else if (value.Contains(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NegativeInfinitySymbol))
            {
                SetInfMinus();
                return;
            }

            string decimalpoint = System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;

            char[] digitChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ',', '.' };

            //Read in the integer part up the the decimal point.
            bool sign = false;
            value = value.Trim();

            int i = 0;

            if (value.Length > i && value[i] == '-')
            {
                sign = true;
                i++;
            }

            if (value.Length > i && value[i] == '+')
            {
                i++;
            }

            for ( ; i < value.Length; i++)
            {
                //break on decimal point
                if (value[i] == decimalpoint[0]) break;

                int digit = Array.IndexOf(digitChars, value[i]);
                if (digit < 0) break;

                //Ignore place separators (assumed either , or .)
                if (digit > 9) continue;

                if (i > 0) iPart.Mul(ten);
                iPart.Add(new BigFloat(digit, extendedPres));
            }

            //If we've run out of characters, assign everything and return
            if (i == value.Length)
            {
                iPart.mantissa.Sign = sign;
                exponent = iPart.exponent;
                if (mantissa.AssignHigh(iPart.mantissa)) exponent++;
                return;
            }

            //Assign the characters after the decimal point to fPart
            if (value[i] == '.' && i < value.Length - 1)
            {
                BigFloat RecipToUse = new BigFloat(tenRCP);

                for (i++; i < value.Length; i++)
                {
                    int digit = Array.IndexOf(digitChars, value[i]);
                    if (digit < 0) break;
                    BigFloat temp = new BigFloat(digit, extendedPres);
                    temp.Mul(RecipToUse);
                    RecipToUse.Mul(tenRCP);
                    fPart.Add(temp);
                }
            }

            //If we're run out of characters, add fPart and iPart and return
            if (i == value.Length)
            {
                iPart.Add(fPart);
                iPart.mantissa.Sign = sign;
                exponent = iPart.exponent;
                if (mantissa.AssignHigh(iPart.mantissa)) exponent++;
                return;
            }

            if (value[i] == '+' || value[i] == '-') i++;

            if (i == value.Length)
            {
                iPart.Add(fPart);
                iPart.mantissa.Sign = sign;
                exponent = iPart.exponent;
                if (mantissa.AssignHigh(iPart.mantissa)) exponent++;
                return;
            }

            //Look for exponential notation.
            if ((value[i] == 'e' || value[i] == 'E') && i < value.Length - 1)
            {
                //Convert the exponent to an int.
                int exp;

                try
                {
                    exp = System.Convert.ToInt32(new string(value.ToCharArray(i + 1, value.Length - (i + 1))));
                }
                catch (Exception)
                {
                    iPart.Add(fPart);
                    iPart.mantissa.Sign = sign;
                    exponent = iPart.exponent;
                    if (mantissa.AssignHigh(iPart.mantissa)) exponent++;
                    return;
                }

                //Raise or lower 10 to the power of the exponent
                BigFloat acc = new BigFloat(1, extendedPres);
                BigFloat temp = new BigFloat(1, extendedPres);

                int powerTemp = exp;

                BigFloat multiplierToUse;

                if (exp < 0)
                {
                    multiplierToUse = new BigFloat(tenRCP);
                    powerTemp = -exp;
                }
                else
                {
                    multiplierToUse = new BigFloat(ten);
                }

                //Fast power function
                while (powerTemp != 0)
                {
                    temp.Mul(multiplierToUse);
                    multiplierToUse.Assign(temp);

                    if ((powerTemp & 1) != 0)
                    {
                        acc.Mul(temp);
                    }

                    powerTemp >>= 1;
                }

                iPart.Add(fPart);
                iPart.Mul(acc);
                iPart.mantissa.Sign = sign;
                exponent = iPart.exponent;
                if (mantissa.AssignHigh(iPart.mantissa)) exponent++;

                return;
            }

            iPart.Add(fPart);
            iPart.mantissa.Sign = sign;
            exponent = iPart.exponent;
            if (mantissa.AssignHigh(iPart.mantissa)) exponent++;

        }
Beispiel #4
0
        private static void CalculateEOnly(int numBits)
        {
            PrecisionSpec extendedPrecision = new PrecisionSpec(numBits + 1, PrecisionSpec.BaseType.BIN);
            PrecisionSpec normalPrecision = new PrecisionSpec(numBits, PrecisionSpec.BaseType.BIN);

            int iExponent = (int)(Math.Sqrt(numBits));

            BigFloat factorial = new BigFloat(1, extendedPrecision);
            BigFloat constant = new BigFloat(1, extendedPrecision);
            constant.exponent -= iExponent;
            BigFloat numerator = new BigFloat(constant);
            BigFloat reciprocal;

            //Calculate the 2^iExponent th root of e
            BigFloat e = new BigFloat(1, extendedPrecision);

            int i;
            for (i = 1; i < Int32.MaxValue; i++)
            {
                BigFloat number = new BigFloat(i, extendedPrecision);
                factorial.Mul(number);
                reciprocal = factorial.Reciprocal();
                reciprocal.Mul(numerator);

                if (-reciprocal.exponent > numBits) break;

                e.Add(reciprocal);
                numerator.Mul(constant);
                System.GC.Collect();
            }

            for (i = 0; i < iExponent; i++)
            {
                numerator.Assign(e);
                e.Mul(numerator);
            }

            //Set the cached static values.
            eCache = new BigFloat(e, normalPrecision);
            eRCPCache = new BigFloat(e.Reciprocal(), normalPrecision);
        }
Beispiel #5
0
        /// <summary>
        /// Uses the Gauss-Legendre formula for pi
        /// Taken from http://en.wikipedia.org/wiki/Gauss%E2%80%93Legendre_algorithm
        /// </summary>
        /// <param name="numBits"></param>
        private static void CalculatePi(int numBits)
        {
            int bits = numBits + 32;
            //Precision extend taken out.
            PrecisionSpec normalPres = new PrecisionSpec(numBits, PrecisionSpec.BaseType.BIN);
            PrecisionSpec extendedPres = new PrecisionSpec(bits, PrecisionSpec.BaseType.BIN);

            if (scratch.Precision.NumBits != bits)
            {
                scratch = new BigInt(extendedPres);
            }

            //a0 = 1
            BigFloat an = new BigFloat(1, extendedPres);

            //b0 = 1/sqrt(2)
            BigFloat bn = new BigFloat(2, extendedPres);
            bn.Sqrt();
            bn.exponent--;

            //to = 1/4
            BigFloat tn = new BigFloat(1, extendedPres);
            tn.exponent -= 2;

            int pn = 0;

            BigFloat anTemp = new BigFloat(extendedPres);

            int iteration = 0;
            int cutoffBits = numBits >> 5;

            for (iteration = 0; ; iteration++)
            {
                //Save a(n)
                anTemp.Assign(an);

                //Calculate new an
                an.Add(bn);
                an.exponent--;

                //Calculate new bn
                bn.Mul(anTemp);
                bn.Sqrt();

                //Calculate new tn
                anTemp.Sub(an);
                anTemp.mantissa.SquareHiFast(scratch);
                anTemp.exponent += anTemp.exponent + pn + 1 - anTemp.mantissa.Normalise();
                tn.Sub(anTemp);

                anTemp.Assign(an);
                anTemp.Sub(bn);

                if (anTemp.exponent < -(bits - cutoffBits)) break;

                //New pn
                pn++;
            }

            an.Add(bn);
            an.mantissa.SquareHiFast(scratch);
            an.exponent += an.exponent + 1 - an.mantissa.Normalise();
            tn.exponent += 2;
            an.Div(tn);

            pi = new BigFloat(an, normalPres);
            piBy2 = new BigFloat(pi);
            piBy2.exponent--;
            twoPi = new BigFloat(pi, normalPres);
            twoPi.exponent++;
            piRecip = new BigFloat(an.Reciprocal(), normalPres);
            twoPiRecip = new BigFloat(piRecip);
            twoPiRecip.exponent--;
            //1/3 is going to be useful for sin.
            threeRecip = new BigFloat((new BigFloat(3, extendedPres)).Reciprocal(), normalPres);
        }
Beispiel #6
0
        private static void CalculateFactorials(int numBits)
        {
            System.Collections.Generic.List<BigFloat> list = new System.Collections.Generic.List<BigFloat>(64);
            System.Collections.Generic.List<BigFloat> list2 = new System.Collections.Generic.List<BigFloat>(64);

            PrecisionSpec extendedPrecision = new PrecisionSpec(numBits + 1, PrecisionSpec.BaseType.BIN);
            PrecisionSpec normalPrecision = new PrecisionSpec(numBits, PrecisionSpec.BaseType.BIN);

            BigFloat factorial = new BigFloat(1, extendedPrecision);
            BigFloat reciprocal;

            //Calculate e while we're at it
            BigFloat e = new BigFloat(1, extendedPrecision);

            list.Add(new BigFloat(factorial, normalPrecision));

            for (int i = 1; i < Int32.MaxValue; i++)
            {
                BigFloat number = new BigFloat(i, extendedPrecision);
                factorial.Mul(number);

                if (factorial.exponent > numBits) break;

                list2.Add(new BigFloat(factorial, normalPrecision));
                reciprocal = factorial.Reciprocal();

                e.Add(reciprocal);
                list.Add(new BigFloat(reciprocal, normalPrecision));
            }

            //Set the cached static values.
            inverseFactorialCache = list.ToArray();
            factorialCache = list2.ToArray();
            invFactorialCutoff = numBits;
            eCache = new BigFloat(e, normalPrecision);
            eRCPCache = new BigFloat(e.Reciprocal(), normalPrecision);
        }
Beispiel #7
0
        private static BigFloat R(BigFloat a0, BigFloat b0)
        {
            //Precision extend taken out.
            int bits = a0.mantissa.Precision.NumBits;
            PrecisionSpec extendedPres = new PrecisionSpec(bits, PrecisionSpec.BaseType.BIN);
            BigFloat an = new BigFloat(a0, extendedPres);
            BigFloat bn = new BigFloat(b0, extendedPres);
            BigFloat sum = new BigFloat(extendedPres);
            BigFloat term = new BigFloat(extendedPres);
            BigFloat temp1 = new BigFloat(extendedPres);
            BigFloat one = new BigFloat(1, extendedPres);

            int iteration = 0;

            for (iteration = 0; ; iteration++)
            {
                //Get the sum term for this iteration.
                term.Assign(an);
                term.Mul(an);
                temp1.Assign(bn);
                temp1.Mul(bn);
                //term = an^2 - bn^2
                term.Sub(temp1);
                //term = 2^(n-1) * (an^2 - bn^2)
                term.exponent += iteration - 1;
                sum.Add(term);

                if (term.exponent < -(bits - 8)) break;

                //Calculate the new AGM estimates.
                temp1.Assign(an);
                an.Add(bn);
                //a(n+1) = (an + bn) / 2
                an.MulPow2(-1);

                //b(n+1) = sqrt(an*bn)
                bn.Mul(temp1);
                bn.Sqrt();
            }

            one.Sub(sum);
            one = one.Reciprocal();
            return new BigFloat(one, a0.mantissa.Precision);
        }
Beispiel #8
0
        private static BigFloat TenPow(int power, PrecisionSpec precision)
        {
            BigFloat acc = new BigFloat(1, precision);
            BigFloat temp = new BigFloat(1, precision);

            int powerTemp = power;

            BigFloat multiplierToUse = new BigFloat(10, precision);

            if (power < 0)
            {
                multiplierToUse = multiplierToUse.Reciprocal();
                powerTemp = -power;
            }

            //Fast power function
            while (powerTemp != 0)
            {
                temp.Mul(multiplierToUse);
                multiplierToUse.Assign(temp);

                if ((powerTemp & 1) != 0)
                {
                    acc.Mul(temp);
                }

                powerTemp >>= 1;
            }

            return acc;
        }
Beispiel #9
0
        /// <summary>
        /// Calculates ln(2) and returns -10^(n/2 + a bit) for reuse, using the AGM method as described in
        /// http://lacim.uqam.ca/~plouffe/articles/log2.pdf
        /// </summary>
        /// <param name="numBits"></param>
        /// <returns></returns>
        private static void CalculateLog2(int numBits)
        {
            //Use the AGM method formula to get log2 to N digits.
            //R(a0, b0) = 1 / (1 - Sum(2^-n*(an^2 - bn^2)))
            //log(1/2) = R(1, 10^-n) - R(1, 10^-n/2)
            PrecisionSpec normalPres = new PrecisionSpec(numBits, PrecisionSpec.BaseType.BIN);
            PrecisionSpec extendedPres = new PrecisionSpec(numBits + 1, PrecisionSpec.BaseType.BIN);
            BigFloat a0 = new BigFloat(1, extendedPres);
            BigFloat b0 = TenPow(-(int)((double)((numBits >> 1) + 2) * 0.302), extendedPres);
            BigFloat pow10saved = new BigFloat(b0);
            BigFloat firstAGMcacheSaved = new BigFloat(extendedPres);

            //save power of 10 (in normal precision)
            pow10cache = new BigFloat(b0, normalPres);

            ln2cache = R(a0, b0);

            //save the first half of the log calculation
            firstAGMcache = new BigFloat(ln2cache, normalPres);
            firstAGMcacheSaved.Assign(ln2cache);

            b0.MulPow2(-1);
            ln2cache.Sub(R(a0, b0));

            //Convert to log(2)
            ln2cache.mantissa.Sign = false;

            //Save magic constant for newton log
            //First guess in range 1 <= x < 2 is x0 = ln2 * (x - 1) + C
            logNewtonConstant = new BigFloat(ln2cache);
            logNewtonConstant.Mul(new BigFloat(3, extendedPres));
            logNewtonConstant.exponent--;
            logNewtonConstant.Sub(new BigFloat(1, extendedPres));
            logNewtonConstant = new BigFloat(logNewtonConstant, normalPres);

            //Save the inverse.
            log2ecache = new BigFloat(ln2cache);
            log2ecache = new BigFloat(log2ecache.Reciprocal(), normalPres);

            //Now cache log10
            //Because the log functions call this function to the precision to which they
            //are called, we cannot call them without causing an infinite loop, so we need
            //to inline the code.
            log10recip = new BigFloat(10, extendedPres);

            {
                int power2 = log10recip.exponent + 1;
                log10recip.exponent = -1;

                //BigFloat res = new BigFloat(firstAGMcache);
                BigFloat ax = new BigFloat(1, extendedPres);
                BigFloat bx = new BigFloat(pow10saved);
                bx.Mul(log10recip);

                BigFloat r = R(ax, bx);

                log10recip.Assign(firstAGMcacheSaved);
                log10recip.Sub(r);

                ax.Assign(ln2cache);
                ax.Mul(new BigFloat(power2, log10recip.mantissa.Precision));
                log10recip.Add(ax);
            }

            log10recip = log10recip.Reciprocal();
            log10recip = new BigFloat(log10recip, normalPres);


            //Trim to n bits
            ln2cache = new BigFloat(ln2cache, normalPres);
        }
Beispiel #10
0
        /// <summary>
        /// Returns a base-10 string representing the number.
        /// 
        /// Note: This is inefficient and possibly inaccurate. Please use with enough
        /// rounding digits (set using the RoundingDigits property) to ensure accuracy
        /// </summary>
        public override string ToString()
        {
            if (IsSpecialValue)
            {
                SpecialValueType s = SpecialValue;
                if (s == SpecialValueType.ZERO)
                {
                    return String.Format("0{0}0", System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator);
                }
                else if (s == SpecialValueType.INF_PLUS)
                {
                    return System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PositiveInfinitySymbol;
                }
                else if (s == SpecialValueType.INF_MINUS)
                {
                    return System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NegativeInfinitySymbol;
                }
                else if (s == SpecialValueType.NAN)
                {
                    return System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NaNSymbol;
                }
                else
                {
                    return "Unrecognised special type";
                }
            }

            if (scratch.Precision.NumBits != mantissa.Precision.NumBits)
            {
                scratch = new BigInt(mantissa.Precision);
            }

            //The mantissa expresses 1.xxxxxxxxxxx
            //The highest possible value for the mantissa without the implicit 1. is 0.9999999...
            scratch.Assign(mantissa);
            //scratch.Round(3);
            scratch.Sign = false;
            BigInt denom = new BigInt("0", mantissa.Precision);
            denom.SetBit(mantissa.Precision.NumBits - 1);

            bool useExponentialNotation = false;
            int halfBits = mantissa.Precision.NumBits / 2;
            if (halfBits > 60) halfBits = 60;
            int precDec = 10;

            if (exponent > 0)
            {
                if (exponent < halfBits)
                {
                    denom.RSH(exponent);
                }
                else
                {
                    useExponentialNotation = true;
                }
            }
            else if (exponent < 0)
            {
                int shift = -(exponent);
                if (shift < precDec)
                {
                    scratch.RSH(shift);
                }
                else
                {
                    useExponentialNotation = true;
                }
            }

            string output;

            if (useExponentialNotation)
            {
                int absExponent = exponent;
                if (absExponent < 0) absExponent = -absExponent;
                int powerOf10 = (int)((double)absExponent * Math.Log10(2.0));

                //Use 1 extra digit of precision (this is actually 32 bits more, nb)
                BigFloat thisFloat = new BigFloat(this, new PrecisionSpec(mantissa.Precision.NumBits + 1, PrecisionSpec.BaseType.BIN));
                thisFloat.mantissa.Sign = false;

                //Multiplicative correction factor to bring number into range.
                BigFloat one = new BigFloat(1, new PrecisionSpec(mantissa.Precision.NumBits + 1, PrecisionSpec.BaseType.BIN));
                BigFloat ten = new BigFloat(10, new PrecisionSpec(mantissa.Precision.NumBits + 1, PrecisionSpec.BaseType.BIN));
                BigFloat tenRCP = ten.Reciprocal();

                //Accumulator for the power of 10 calculation.
                BigFloat acc = new BigFloat(1, new PrecisionSpec(mantissa.Precision.NumBits + 1, PrecisionSpec.BaseType.BIN));

                BigFloat tenToUse;

                if (exponent > 0)
                {
                    tenToUse = new BigFloat(tenRCP, new PrecisionSpec(mantissa.Precision.NumBits + 1, PrecisionSpec.BaseType.BIN));
                }
                else
                {
                    tenToUse = new BigFloat(ten, new PrecisionSpec(mantissa.Precision.NumBits + 1, PrecisionSpec.BaseType.BIN));
                }

                BigFloat tenToPower = new BigFloat(1, new PrecisionSpec(mantissa.Precision.NumBits + 1, PrecisionSpec.BaseType.BIN));

                int powerTemp = powerOf10;

                //Fast power function
                while (powerTemp != 0)
                {
                    tenToPower.Mul(tenToUse);
                    tenToUse.Assign(tenToPower);

                    if ((powerTemp & 1) != 0)
                    {
                        acc.Mul(tenToPower);
                    }

                    powerTemp >>= 1;
                }

                thisFloat.Mul(acc);

                //If we are out of range, correct.           
                if (thisFloat.GreaterThan(ten))
                {
                    thisFloat.Mul(tenRCP);
                    if (exponent > 0)
                    {
                        powerOf10++;
                    }
                    else
                    {
                        powerOf10--;
                    }
                }
                else if (thisFloat.LessThan(one))
                {
                    thisFloat.Mul(ten);
                    if (exponent > 0)
                    {
                        powerOf10--;
                    }
                    else
                    {
                        powerOf10++;
                    }
                }

                //Restore the precision and the sign.
                BigFloat printable = new BigFloat(thisFloat, mantissa.Precision);
                printable.mantissa.Sign = mantissa.Sign;
                output = printable.ToString();

                if (exponent < 0) powerOf10 = -powerOf10;

                output = String.Format("{0}E{1}", output, powerOf10);
            }
            else
            {
                BigInt bigDigit = BigInt.Div(scratch, denom);
                bigDigit.Sign = false;
                scratch.Sub(BigInt.Mul(denom, bigDigit));

                if (mantissa.Sign)
                {
                    output = String.Format("-{0}.", bigDigit);
                }
                else
                {
                    output = String.Format("{0}.", bigDigit);
                }

                denom = BigInt.Div(denom, 10u);

                while (!denom.IsZero())
                {
                    uint digit = (uint)BigInt.Div(scratch, denom);
                    if (digit == 10) digit--;
                    scratch.Sub(BigInt.Mul(denom, digit));
                    output = String.Format("{0}{1}", output, digit);
                    denom = BigInt.Div(denom, 10u);
                }

                output = RoundString(output, RoundingDigits);
            }

            return output;
        }