Esempio n. 1
0
        /**
         *  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);
        }
Esempio n. 2
0
        /**
         *  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);
        }
Esempio n. 3
0
        /**
         * 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);
            }
        }