/** * Compute sine 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) * @return sin(xa + xb) */ public static double Quadrant(double xa, double xb) { int idx = (int)((xa * 8.0) + 0.5); double epsilon = xa - BitOps.EIGHTHS[idx]; //idx*0.125; // Table lookups double sintA = SINE_TABLE_A[idx]; double sintB = 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 = 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 */ double result; /* 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; 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; /* * t = sintA*cosEpsB; * c = a + t; * d = -(c - a - t); * a = c; * b = b + d; * * t = costA*sinEpsB; * c = a + t; * d = -(c - a - t); * a = c; * b = b + d; */ b = b + sintB + costB * sinEpsA + sintB * cosEpsB + costB * sinEpsB; /* * t = sintB; * c = a + t; * d = -(c - a - t); * a = c; * b = b + d; * * t = costB*sinEpsA; * c = a + t; * d = -(c - a - t); * a = c; * b = b + d; * * t = sintB*cosEpsB; * c = a + t; * d = -(c - a - t); * a = c; * b = b + d; * * t = costB*sinEpsB; * c = a + t; * d = -(c - a - t); * a = c; * b = b + d; */ if (xb != 0.0) { t = ((costA + costB) * (cosEpsA + cosEpsB) - (sintA + sintB) * (sinEpsA + sinEpsB)) * xb; // approximate cosine*xb c = a + t; d = -(c - a - t); a = c; b = b + d; } result = a + b; return(result); }
/** * 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); }
/** * Sine function. * * @param x Argument. * @return sin(x) */ public static double Calc(double x) { bool negative = false; int quadrant = 0; double xa; double xb = 0.0; /* Take absolute value of the input */ xa = x; if (x < 0) { negative = true; xa = -xa; } /* Check for zero and negative zero */ if (xa == 0.0) { long bits = BitConverter.DoubleToInt64Bits(x); if (bits < 0) { return(-0.0); } return(0.0); } if (xa == Double.PositiveInfinity) { return(Double.NaN); } /* Perform any argument reduction */ if (xa > 3294198.0) { // PI * (2**20) // Argument too big for CodyWaite reduction. Must use // PayneHanek. double[] reduceResults = new double[3]; PayneHanek.Reduce(xa, reduceResults); quadrant = ((int)reduceResults[0]) & 3; xa = reduceResults[1]; xb = reduceResults[2]; } else if (xa > 1.5707963267948966) { CodyWaite cw = new CodyWaite(xa); quadrant = cw.getK() & 3; xa = cw.getRemA(); xb = cw.getRemB(); } if (negative) { quadrant ^= 2; // Flip bit 1 } switch (quadrant) { case 0: return(Quadrant(xa, xb)); case 1: return(Cosine.Quadrant(xa, xb)); case 2: return(-Quadrant(xa, xb)); case 3: return(-Cosine.Quadrant(xa, xb)); default: return(Double.NaN); } }