Beispiel #1
0
        /// <summary>
        /// Calculates Sin(x):
        /// This takes a little longer and is less accurate if the input is out of the range (-pi, pi].
        /// </summary>
        public void Sin()
        {
            if (IsSpecialValue)
            {
                //Sin(x) has no limit as x->inf
                if (SpecialValue == SpecialValueType.INF_MINUS || SpecialValue == SpecialValueType.INF_PLUS)
                {
                    SetNaN();
                }

                return;
            }

            //Convert to positive range (0 <= x < inf)
            bool sign = mantissa.Sign;
            mantissa.Sign = false;

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

            if (inverseFactorialCache == null || invFactorialCutoff != mantissa.Precision.NumBits)
            {
                CalculateFactorials(mantissa.Precision.NumBits);
            }

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

            //Rescale into range 0 <= x < pi
            if (GreaterThan(pi))
            {
                //sin(pi + a) = sin(pi)cos(a) + sin(a)cos(pi) = 0 - sin(a) = -sin(a)
                Sub(pi);
                sign = !sign;
            }

            BigFloat temp = new BigFloat(mantissa.Precision);

            //Rescale into range 0 <= x < pi/2
            if (GreaterThan(piBy2))
            {
                temp.Assign(this);
                Assign(pi);
                Sub(temp);
            }

            //Rescale into range 0 <= x < pi/6 to accelerate convergence.
            //This is done using sin(3x) = 3sin(x) - 4sin^3(x)
            Mul(threeRecip);

            if (mantissa.IsZero())
            {
                exponent = 0;
                return;
            }

            BigFloat term = new BigFloat(this);

            BigFloat square = new BigFloat(this);
            square.Mul(term);

            BigFloat sum = new BigFloat(this);

            bool termSign = true;
            int length = inverseFactorialCache.Length;
            int numBits = mantissa.Precision.NumBits;

            for (int i = 3; i < length; i += 2)
            {
                term.Mul(square);
                temp.Assign(inverseFactorialCache[i]);
                temp.Mul(term);
                temp.mantissa.Sign = termSign;
                termSign = !termSign;

                if (temp.exponent < -numBits) break;

                sum.Add(temp);
            }

            //Restore the triple-angle: sin(3x) = 3sin(x) - 4sin^3(x)
            Assign(sum);
            sum.Mul(this);
            sum.Mul(this);
            Mul(new BigFloat(3, mantissa.Precision));
            sum.exponent += 2;
            Sub(sum);

            //Restore the sign
            mantissa.Sign = sign;
        }
Beispiel #2
0
 /// <summary>
 /// Returns the fractional (non-integer component of the input)
 /// </summary>
 /// <param name="n1">The input number</param>
 public static BigFloat FPart(BigFloat n1)
 {
     BigFloat res = new BigFloat(n1);
     n1.FPart();
     return n1;
 }
Beispiel #3
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;
        }