Esempio n. 1
0
        /**
         *  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);
        }
Esempio n. 2
0
        /**
         *  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);
        }
Esempio n. 3
0
        /**
         * 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));
        }
Esempio n. 4
0
        /** Internal helper function to compute arctangent.
         * @param xa number from which arctangent is requested
         * @param xb extra bits for x (may be 0.0)
         * @param leftPlane if true, result angle must be put in the left half plane
         * @return atan(xa + xb) (or angle shifted by {@code PI} if leftPlane is true)
         */
        private static double Arc(double xa, double xb, bool leftPlane)
        {
            bool negate = false;
            int  idx;

            if (xa == 0.0)
            { // Matches +/- 0.0; return correct sign
                return(leftPlane ? BitOps.CopySign(Math.PI, xa) : xa);
            }

            if (xa < 0)
            {
                // negative
                xa     = -xa;
                xb     = -xb;
                negate = true;
            }

            if (xa > 1.633123935319537E16)
            { // Very large input
                return((negate ^ leftPlane) ? (-Math.PI * F_1_2) : (Math.PI * F_1_2));
            }

            /* Estimate the closest tabulated arctan value, compute eps = xa-tangentTable */
            if (xa < 1)
            {
                idx = (int)(((-1.7168146928204136 * xa * xa + 8.0) * xa) + 0.5);
            }
            else
            {
                double oneOverXa = 1 / xa;
                idx = (int)(-((-1.7168146928204136 * oneOverXa * oneOverXa + 8.0) * oneOverXa) + 13.07);
            }
            double epsA = xa - TANGENT_TABLE_A[idx];
            double epsB = -(epsA - xa + TANGENT_TABLE_A[idx]);

            epsB += xb - TANGENT_TABLE_B[idx];

            double temp = epsA + epsB;

            epsB = -(temp - epsA - epsB);
            epsA = temp;

            /* Compute eps = eps / (1.0 + xa*tangent) */
            temp = xa * BitOps.HEX_40000000;
            double ya = xa + temp - temp;
            double yb = xb + xa - ya;

            xa  = ya;
            xb += yb;

            //if (idx > 8 || idx == 0)
            if (idx == 0)
            {
                /* If the slope of the arctan is gentle enough (< 0.45), this approximation will suffice */
                //double denom = 1.0 / (1.0 + xa*tangentTableA[idx] + xb*tangentTableA[idx] + xa*tangentTableB[idx] + xb*tangentTableB[idx]);
                double denom = 1d / (1d + (xa + xb) * (TANGENT_TABLE_A[idx] + TANGENT_TABLE_B[idx]));
                //double denom = 1.0 / (1.0 + xa*tangentTableA[idx]);
                ya = epsA * denom;
                yb = epsB * denom;
            }
            else
            {
                double temp2 = xa * TANGENT_TABLE_A[idx];
                double za    = 1d + temp2;
                double zb    = -(za - 1d - temp2);
                temp2 = xb * TANGENT_TABLE_A[idx] + xa * TANGENT_TABLE_B[idx];
                temp  = za + temp2;
                zb   += -(temp - za - temp2);
                za    = temp;

                zb += xb * TANGENT_TABLE_B[idx];
                ya  = epsA / za;

                temp = ya * BitOps.HEX_40000000;
                double yaa = (ya + temp) - temp;
                double yab = ya - yaa;

                temp = za * BitOps.HEX_40000000;
                double zaa = (za + temp) - temp;
                double zab = za - zaa;

                /* Correct for rounding in division */
                yb = (epsA - yaa * zaa - yaa * zab - yab * zaa - yab * zab) / za;

                yb += -epsA * zb / za / za;
                yb += epsB / za;
            }


            epsA = ya;
            epsB = yb;

            /* Evaluate polynomial */
            double epsA2 = epsA * epsA;

            /*
             * yb = -0.09001346640161823;
             * yb = yb * epsA2 + 0.11110718400605211;
             * yb = yb * epsA2 + -0.1428571349122913;
             * yb = yb * epsA2 + 0.19999999999273194;
             * yb = yb * epsA2 + -0.33333333333333093;
             * yb = yb * epsA2 * epsA;
             */

            yb = 0.07490822288864472;
            yb = yb * epsA2 + -0.09088450866185192;
            yb = yb * epsA2 + 0.11111095942313305;
            yb = yb * epsA2 + -0.1428571423679182;
            yb = yb * epsA2 + 0.19999999999923582;
            yb = yb * epsA2 + -0.33333333333333287;
            yb = yb * epsA2 * epsA;


            ya = epsA;

            temp = ya + yb;
            yb   = -(temp - ya - yb);
            ya   = temp;

            /* Add in effect of epsB.   atan'(x) = 1/(1+x^2) */
            yb += epsB / (1d + epsA * epsA);

            //result = yb + eighths[idx] + ya;
            double za = BitOps.EIGHTHS[idx] + ya;
            double zb = -(za - BitOps.EIGHTHS[idx] - ya);

            temp = za + yb;
            zb  += -(temp - za - yb);
            za   = temp;

            double result  = za + zb;
            double resultb = -(result - za - zb);

            if (leftPlane)
            {
                // Result is in the left plane
                double pia = 1.5707963267948966 * 2;
                double pib = 6.123233995736766E-17 * 2;

                za  = pia - result;
                zb  = -(za - pia + result);
                zb += pib - resultb;

                result  = za + zb;
                resultb = -(result - za - zb);
            }


            if (negate ^ leftPlane)
            {
                result = -result;
            }

            return(result);
        }
Esempio n. 5
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));
        }