Пример #1
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);
        }
Пример #2
0
 /// <summary>
 /// Two-variable iterative square root, taken from
 /// http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#A_two-variable_iterative_method
 /// </summary>
 /// <remarks>This is quite a fast function, as elementary functions go. You can expect it to take
 /// about twice as long as a floating-point division.
 /// </remarks>
 public static BigFloat Sqrt(BigFloat n1)
 {
     BigFloat res = new BigFloat(n1);
     res.Sqrt();
     return res;
 }
Пример #3
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);
        }
Пример #4
0
        /// <summary>
        /// Arccosh(): the inverse cosh() function
        /// </summary>
        public void Arccosh()
        {
            //acosh isn't defined for x < 1
            if (IsSpecialValue)
            {
                if (SpecialValue == SpecialValueType.INF_MINUS || SpecialValue == SpecialValueType.ZERO)
                {
                    SetNaN();
                    return;
                }

                return;
            }

            BigFloat one = new BigFloat(1, mantissa.Precision);
            if (LessThan(one))
            {
                SetNaN();
                return;
            }

            BigFloat temp = new BigFloat(this);
            temp.Mul(this);
            temp.Sub(one);
            temp.Sqrt();
            Add(temp);
            Log();
        }
Пример #5
0
        /// <summary>
        /// Arcsinh(): the inverse sinh function
        /// </summary>
        public void Arcsinh()
        {
            //Just let all special values fall through
            if (IsSpecialValue)
            {
                return;
            }

            BigFloat temp = new BigFloat(this);
            temp.Mul(this);
            temp.Add(new BigFloat(1, mantissa.Precision));
            temp.Sqrt();
            Add(temp);
            Log();
        }
Пример #6
0
        /// <summary>
        /// arctan(): the inverse function of sin(), range of (-pi/2..pi/2)
        /// </summary>
        public void Arctan()
        {
            //With 2 argument reductions, we increase precision by a minimum of 4 bits per term.
            int numBits = mantissa.Precision.NumBits;
            int maxTerms = numBits >> 2;

            if (pi == null || pi.mantissa.Precision.NumBits != numBits)
            {
                CalculatePi(mantissa.Precision.NumBits);
            }

            //Make domain positive
            bool sign = mantissa.Sign;
            mantissa.Sign = false;

            if (IsSpecialValue)
            {
                if (SpecialValue == SpecialValueType.INF_MINUS || SpecialValue == SpecialValueType.INF_PLUS)
                {
                    Assign(piBy2);
                    mantissa.Sign = sign;
                    return;
                }

                return;
            }

            if (reciprocals == null || reciprocals[0].mantissa.Precision.NumBits != numBits || reciprocals.Length < maxTerms)
            {
                CalculateReciprocals(numBits, maxTerms);
            }

            bool invert = false;
            BigFloat one = new BigFloat(1, mantissa.Precision);

            //Invert if outside of convergence
            if (GreaterThan(one))
            {
                invert = true;
                Assign(Reciprocal());
            }

            //Reduce using half-angle formula:
            //arctan(2x) = 2 arctan (x / (1 + sqrt(1 + x)))

            //First reduction (guarantees 2 bits per iteration)
            BigFloat temp = new BigFloat(this);
            temp.Mul(this);
            temp.Add(one);
            temp.Sqrt();
            temp.Add(one);
            this.Div(temp);

            //Second reduction (guarantees 4 bits per iteration)
            temp.Assign(this);
            temp.Mul(this);
            temp.Add(one);
            temp.Sqrt();
            temp.Add(one);
            this.Div(temp);

            //Actual series calculation
            int length = reciprocals.Length;
            BigFloat term = new BigFloat(this);

            //pow = x^2
            BigFloat pow = new BigFloat(this);
            pow.Mul(this);

            BigFloat sum = new BigFloat(this);

            for (int i = 1; i < length; i++)
            {
                //u(n) = u(n-1) * x^2
                //t(n) = u(n) / (2n+1)
                term.Mul(pow);
                term.Sign = !term.Sign;
                temp.Assign(term);
                temp.Mul(reciprocals[i]);

                if (temp.exponent < -numBits) break;

                sum.Add(temp);
            }

            //Undo the reductions.
            Assign(sum);
            exponent += 2;

            if (invert)
            {
                //Assign(Reciprocal());
                mantissa.Sign = true;
                Add(piBy2);
            }

            if (sign)
            {
                mantissa.Sign = sign;
            }
        }
Пример #7
0
        /// <summary>
        /// arcsin(): the inverse function of sin(), range of (-pi/2..pi/2)
        /// </summary>
        public void Arcsin()
        {
            if (IsSpecialValue)
            {
                if (SpecialValue == SpecialValueType.INF_MINUS || SpecialValue == SpecialValueType.INF_PLUS || SpecialValue == SpecialValueType.NAN)
                {
                    SetNaN();
                    return;
                }

                return;
            }

            BigFloat one = new BigFloat(1, mantissa.Precision);
            BigFloat plusABit = new BigFloat(1, mantissa.Precision);
            plusABit.exponent -= (mantissa.Precision.NumBits - (mantissa.Precision.NumBits >> 6));
            BigFloat onePlusABit = new BigFloat(1, mantissa.Precision);
            onePlusABit.Add(plusABit);

            bool sign = mantissa.Sign;
            mantissa.Sign = false;

            if (GreaterThan(onePlusABit))
            {
                SetNaN();
            }
            else if (LessThan(one))
            {
                BigFloat temp = new BigFloat(this);
                temp.Mul(this);
                temp.Sub(one);
                temp.mantissa.Sign = !temp.mantissa.Sign;
                temp.Sqrt();
                temp.Add(one);
                Div(temp);
                Arctan();
                exponent++;
                mantissa.Sign = sign;
            }
            else
            {
                if (pi == null || pi.mantissa.Precision.NumBits != mantissa.Precision.NumBits)
                {
                    CalculatePi(mantissa.Precision.NumBits);
                }

                Assign(piBy2);
                if (sign) mantissa.Sign = true;
            }
        }
Пример #8
0
        /// <summary>
        /// Calculates tan(x)
        /// </summary>
        public void Tan()
        {
            if (IsSpecialValue)
            {
                //Tan(x) has no limit as x->inf
                if (SpecialValue == SpecialValueType.INF_MINUS || SpecialValue == SpecialValueType.INF_PLUS)
                {
                    SetNaN();
                }
                else if (SpecialValue == SpecialValueType.ZERO)
                {
                    SetZero();
                }

                return;
            }

            if (pi == null || pi.mantissa.Precision.NumBits != mantissa.Precision.NumBits)
            {
                CalculatePi(mantissa.Precision.NumBits);
            }

            //Work out the sign change (involves replicating some rescaling).
            bool sign = mantissa.Sign;
            mantissa.Sign = false;

            if (mantissa.IsZero())
            {
                return;
            }

            //Rescale into 0 <= x < pi
            if (GreaterThan(pi))
            {
                //There will be an inherent loss of precision doing this.
                BigFloat newAngle = new BigFloat(this);
                newAngle.Mul(piRecip);
                newAngle.FPart();
                newAngle.Mul(pi);
                Assign(newAngle);
            }

            //Rescale to -pi/2 <= x < pi/2
            if (!LessThan(piBy2))
            {
                Sub(pi);
            }

            //Now the sign of the sin determines the sign of the tan.
            //tan(x) = sin(x) / sqrt(1 - sin^2(x))
            Sin();
            BigFloat denom = new BigFloat(this);
            denom.Mul(this);
            denom.Sub(new BigFloat(1, mantissa.Precision));
            denom.mantissa.Sign = !denom.mantissa.Sign;

            if (denom.mantissa.Sign)
            {
                denom.SetZero();
            }

            denom.Sqrt();
            Div(denom);
            if (sign) mantissa.Sign = !mantissa.Sign;
        }