/** * Convert radians to degrees, with error of less than 0.5 ULP * @param x angle in radians * @return x converted into degrees */ public static double toDegrees(double x) { if (Double.IsInfinity(x) || x == 0.0) { // Matches +/- 0.0; return correct sign return(x); } // These are 180/PI split into high and low order bits double facta = 57.2957763671875; double factb = 3.145894820876798E-6; double xa = BitOps.HighPart(x); double xb = x - xa; return(xb * factb + xb * facta + xa * factb + xa * facta); }
/** * Convert degrees to radians, with error of less than 0.5 ULP * @param x angle in degrees * @return x converted into radians */ public static double ToRadians(double x) { if (Double.IsInfinity(x) || x == 0.0) { // Matches +/- 0.0; return correct sign return(x); } // These are PI/180 split into high and low order bits double facta = 0.01745329052209854; double factb = 1.997844754509471E-9; double xa = BitOps.HighPart(x); double xb = x - xa; double result = xb * factb + xb * facta + xa * factb + xa * facta; if (result == 0) { result = result * x; // ensure correct sign if calculation underflows } return(result); }
/** * Two arguments arctangent function * @param y ordinate * @param x abscissa * @return phase angle of point (x,y) between {@code -PI} and {@code PI} */ public static double Arc(double y, double x) { if (y == 0) { double result = x * y; double invx = 1d / x; double invy = 1d / y; if (invx == 0) { // X is infinite if (x > 0) { return(y); // return +/- 0.0 } else { return(BitOps.CopySign(Math.PI, y)); } } if (x < 0 || invx < 0) { if (y < 0 || invy < 0) { return(-Math.PI); } else { return(Math.PI); } } else { return(result); } } // y cannot now be zero if (y == Double.PositiveInfinity) { if (x == Double.PositiveInfinity) { return(Math.PI * F_1_4); } if (x == Double.PositiveInfinity) { return(Math.PI * F_3_4); } return(Math.PI * F_1_2); } if (y == Double.NegativeInfinity) { if (x == Double.PositiveInfinity) { return(-Math.PI * F_1_4); } if (x == Double.NegativeInfinity) { return(-Math.PI * F_3_4); } return(-Math.PI * F_1_2); } if (x == Double.PositiveInfinity) { if (y > 0 || 1 / y > 0) { return(0d); } if (y < 0 || 1 / y < 0) { return(-0d); } } if (x == Double.NegativeInfinity) { if (y > 0.0 || 1 / y > 0.0) { return(Math.PI); } if (y < 0 || 1 / y < 0) { return(-Math.PI); } } // Neither y nor x can be infinite or NAN here if (x == 0) { if (y > 0 || 1 / y > 0) { return(Math.PI * F_1_2); } if (y < 0 || 1 / y < 0) { return(-Math.PI * F_1_2); } } // Compute ratio r = y/x double r = y / x; if (Double.IsInfinity(r)) { // bypass calculations that can create NaN return(Arc(r, 0, x < 0)); } double ra = BitOps.HighPart(r); double rb = r - ra; // Split x double xa = BitOps.HighPart(x); double xb = x - xa; rb += (y - ra * xa - ra * xb - rb * xa - rb * xb) / x; double temp = ra + rb; rb = -(temp - ra - rb); ra = temp; if (ra == 0) { // Fix up the sign so atan works correctly ra = BitOps.CopySign(0d, y); } // Call atan return(Arc(ra, rb, x < 0)); }
/** Compute the arc cosine of a number. * @param x number on which evaluation is done * @return arc cosine of x */ public static double Arc(double x) { if (x > 1.0 || x < -1.0) { return(Double.NaN); } if (x == -1.0) { return(Math.PI); } if (x == 1.0) { return(0.0); } if (x == 0) { return(Math.PI / 2.0); } /* Compute acos(x) = atan(sqrt(1-x*x)/x) */ /* Split x */ double temp = x * BitOps.HEX_40000000; double xa = x + temp - temp; double xb = x - xa; /* Square it */ double ya = xa * xa; double yb = xa * xb * 2.0 + xb * xb; /* Subtract from 1 */ ya = -ya; yb = -yb; double za = 1.0 + ya; double zb = -(za - 1.0 - ya); temp = za + yb; zb += -(temp - za - yb); za = temp; /* Square root */ double y = Math.Sqrt(za); temp = y * BitOps.HEX_40000000; ya = y + temp - temp; yb = y - ya; /* Extend precision of sqrt */ yb += (za - ya * ya - 2 * ya * yb - yb * yb) / (2.0 * y); /* Contribution of zb to sqrt */ yb += zb / (2.0 * y); y = ya + yb; yb = -(y - ya - yb); // Compute ratio r = y/x double r = y / x; // Did r overflow? if (double.IsInfinity(r)) { // x is effectively zero return(Math.PI / 2); // so return the appropriate value } double ra = BitOps.HighPart(r); double rb = r - ra; rb += (y - ra * xa - ra * xb - rb * xa - rb * xb) / x; // Correct for rounding in division rb += yb / x; // Add in effect additional bits of sqrt. temp = ra + rb; rb = -(temp - ra - rb); ra = temp; return(atan(ra, rb, x < 0)); }