Example #1
0
        /**
         * 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));
        }
Example #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);
        }