/** * Compute cosine in the first quadrant by subtracting input from PI/2 and * then calling sinQ. This is more accurate as the input approaches PI/2. * @param xa number from which cosine is requested * @param xb extra bits for x (may be 0.0) * @return cos(xa + xb) */ public static double Quadrant(double xa, double xb) { double pi2a = 1.5707963267948966; double pi2b = 6.123233995736766E-17; double a = pi2a - xa; double b = -(a - pi2a + xa); b += pi2b - xb; return(Sine.Quadrant(a, b)); }
/** * Compute tangent (or cotangent) over the first quadrant. 0 < x < pi/2 * Use combination of table lookup and rational polynomial expansion. * @param xa number from which sine is requested * @param xb extra bits for x (may be 0.0) * @param cotanFlag if true, compute the cotangent instead of the tangent * @return tan(xa+xb) (or cotangent, depending on cotanFlag) */ public static double Quadrant(double xa, double xb, bool cotanFlag) { int idx = (int)((xa * 8.0) + 0.5); double epsilon = xa - BitOps.EIGHTHS[idx]; //idx*0.125; // Table lookups double sintA = Sine.SINE_TABLE_A[idx]; double sintB = Sine.SINE_TABLE_B[idx]; double costA = Cosine.COSINE_TABLE_A[idx]; double costB = Cosine.COSINE_TABLE_B[idx]; // Polynomial eval of sin(epsilon), cos(epsilon) double sinEpsA = epsilon; double sinEpsB = Sine.Poly(epsilon); double cosEpsA = 1.0; double cosEpsB = Cosine.Poly(epsilon); // Split epsilon xa + xb = x double temp = sinEpsA * BitOps.HEX_40000000; double temp2 = (sinEpsA + temp) - temp; sinEpsB += sinEpsA - temp2; sinEpsA = temp2; /* Compute sin(x) by angle addition formula */ /* Compute the following sum: * * result = sintA + costA*sinEpsA + sintA*cosEpsB + costA*sinEpsB + * sintB + costB*sinEpsA + sintB*cosEpsB + costB*sinEpsB; * * Ranges of elements * * xxxtA 0 PI/2 * xxxtB -1.5e-9 1.5e-9 * sinEpsA -0.0625 0.0625 * sinEpsB -6e-11 6e-11 * cosEpsA 1.0 * cosEpsB 0 -0.0625 * */ //result = sintA + costA*sinEpsA + sintA*cosEpsB + costA*sinEpsB + // sintB + costB*sinEpsA + sintB*cosEpsB + costB*sinEpsB; //result = sintA + sintA*cosEpsB + sintB + sintB * cosEpsB; //result += costA*sinEpsA + costA*sinEpsB + costB*sinEpsA + costB * sinEpsB; double a = 0; double b = 0; // Compute sine double t = sintA; double c = a + t; double d = -(c - a - t); a = c; b = b + d; t = costA * sinEpsA; c = a + t; d = -(c - a - t); a = c; b = b + d; b = b + sintA * cosEpsB + costA * sinEpsB; b = b + sintB + costB * sinEpsA + sintB * cosEpsB + costB * sinEpsB; double sina = a + b; double sinb = -(sina - a - b); // Compute cosine a = b = c = d = 0.0; t = costA * cosEpsA; c = a + t; d = -(c - a - t); a = c; b = b + d; t = -sintA * sinEpsA; c = a + t; d = -(c - a - t); a = c; b = b + d; b = b + costB * cosEpsA + costA * cosEpsB + costB * cosEpsB; b = b - (sintB * sinEpsA + sintA * sinEpsB + sintB * sinEpsB); double cosa = a + b; double cosb = -(cosa - a - b); if (cotanFlag) { double tmp; tmp = cosa; cosa = sina; sina = tmp; tmp = cosb; cosb = sinb; sinb = tmp; } /* estimate and correct, compute 1.0/(cosa+cosb) */ /* * double est = (sina+sinb)/(cosa+cosb); * double err = (sina - cosa*est) + (sinb - cosb*est); * est += err/(cosa+cosb); * err = (sina - cosa*est) + (sinb - cosb*est); */ // f(x) = 1/x, f'(x) = -1/x^2 double est = sina / cosa; /* Split the estimate to get more accurate read on division rounding */ temp = est * BitOps.HEX_40000000; double esta = (est + temp) - temp; double estb = est - esta; temp = cosa * BitOps.HEX_40000000; double cosaa = (cosa + temp) - temp; double cosab = cosa - cosaa; //double err = (sina - est*cosa)/cosa; // Correction for division rounding double err = (sina - esta * cosaa - esta * cosab - estb * cosaa - estb * cosab) / cosa; // Correction for division rounding err += sinb / cosa; // Change in est due to sinb err += -sina * cosb / cosa / cosa; // Change in est due to cosb if (xb != 0.0) { // tan' = 1 + tan^2 cot' = -(1 + cot^2) // Approximate impact of xb double xbadj = xb + est * est * xb; if (cotanFlag) { xbadj = -xbadj; } err += xbadj; } return(est + err); }