示例#1
0
        /// <summary>
        /// Constructs a BigFloat from a BigInt, using the specified precision
        /// </summary>
        /// <param name="value"></param>
        /// <param name="mantissaPrec"></param>
        public BigFloat(BigInt value, PrecisionSpec mantissaPrec)
        {
            if (value.IsZero())
            {
                Init(mantissaPrec);
                SetZero();
                return;
            }

            mantissa = new BigInt(value, mantissaPrec);
            exponent = BigInt.GetMSB(value);
            mantissa.Normalise();
        }
示例#2
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;
        }
示例#3
0
        /// <summary>
        /// Calculates 'this'^power
        /// </summary>
        /// <param name="power"></param>
        public void Power(BigInt power)
        {
            if (power.IsZero() || power.sign)
            {
                Zero();
                digitArray[0] = 1;
                return;
            }

            BigInt pow = new BigInt(power);
            BigInt temp = new BigInt(this);
            BigInt powTerm = new BigInt(this);

            pow.Decrement();
            for (; !pow.IsZero(); pow.RSH(1))
            {
                if ((pow.digitArray[0] & 1) == 1)
                {
                    temp.Mul(powTerm);
                }

                powTerm.Square();
            }

            Assign(temp);
        }
示例#4
0
        /// <summary>
        /// This function is used for floating-point division.
        /// </summary>
        /// <param name="n2"></param>
        //Given two numbers:
        //  In floating point 1 <= a, b < 2, meaning that both numbers have their top bits set.
        //  To calculate a / b, maintaining precision, we:
        //    1. Double the number of digits available to both numbers.
        //    2. set a = a * 2^d (where d is the number of digits)
        //    3. calculate the quotient a <- q:  2^(d-1) <= q < 2^(d+1)
        //    4. if a >= 2^d, s = 1, else s = 0
        //    6. shift a down by s, and undo the precision extension
        //    7. return 1 - shift (change necessary to exponent)
        public int DivAndShift(BigInt n2)
        {
            if (n2.IsZero()) return -1;
            if (digitArray.Length != n2.digitArray.Length) MakeSafe(ref n2);

            int oldLength = digitArray.Length;

            //Double the number of digits, and shift a into the higher digits.
            Pad();
            n2.Extend();

            //Do the divide (at double precision, ouch!)
            Div(n2);

            //Shift down if 'this' >= 2^d
            int ret = 1;

            if (digitArray[oldLength] != 0)
            {
                RSH(1);
                ret--;
            }

            SetNumDigits(oldLength);
            n2.SetNumDigits(oldLength);

            return ret;
        }
示例#5
0
        //********************* ToString members **********************

        /// <summary>
        /// Converts this to a string, in the specified base
        /// </summary>
        /// <param name="numberBase">the base to use (min 2, max 16)</param>
        /// <returns>a string representation of the number</returns>
        public string ToString(int numberBase)
        {
            char[] digitChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

            string output = "";

            BigInt clone = new BigInt(this);
            clone.sign = false;

            int numDigits = 0;
            while (!clone.IsZero())
            {
                if (numberBase == 10 && (numDigits % 3) == 0 && numDigits != 0)
                {
                    output = String.Format(",{0}", output);
                }
                else if (numberBase != 10 && (numDigits % 8) == 0 && numDigits != 0)
                {
                    output = String.Format(" {0}", output);
                }

                BigInt div, mod;
                DivMod(clone, (uint)numberBase, out div, out mod);
                int iMod = (int)mod;
                output = String.Format("{0}{1}", digitChars[(int)mod], output);

                numDigits++;

                clone = div;
            }

            if (output.Length == 0) output = String.Format("0");

            if (sign) output = String.Format("-{0}", output);

            return output;
        }
示例#6
0
        /// <summary>
        /// True iff n2 (precision-adjusted to this) == n1
        /// </summary>
        /// <param name="n2"></param>
        /// <returns></returns>
        public bool Equals(BigInt n2)
        {
            if (IsZero() && n2.IsZero()) return true;

            if (sign != n2.sign) return false;

            int Length = digitArray.Length;
            if (n2.digitArray.Length != Length) MakeSafe(ref n2);

            for (int i = 0; i < Length; i++)
            {
                if (digitArray[i] != n2.digitArray[i]) return false;
            }

            return true;
        }