/// <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; }
/// <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; }
/// <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; }