base/math/k_cos.c

Go to the documentation of this file.
00001 /* @(#)k_cos.c 5.1 93/09/24 */
00002 /*
00003  * ====================================================
00004  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
00005  *
00006  * Developed at SunPro, a Sun Microsystems, Inc. business.
00007  * Permission to use, copy, modify, and distribute this
00008  * software is freely granted, provided that this notice 
00009  * is preserved.
00010  * ====================================================
00011  */
00012 
00013 #if defined(LIBM_SCCS) && !defined(lint)
00014 static char rcsid[] = "$NetBSD: k_cos.c,v 1.8 1995/05/10 20:46:22 jtc Exp $";
00015 #endif
00016 
00017 /*
00018  * __kernel_cos( x,  y )
00019  * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164
00020  * Input x is assumed to be bounded by ~pi/4 in magnitude.
00021  * Input y is the tail of x. 
00022  *
00023  * Algorithm
00024  *  1. Since cos(-x) = cos(x), we need only to consider positive x.
00025  *  2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0.
00026  *  3. cos(x) is approximated by a polynomial of degree 14 on
00027  *     [0,pi/4]
00028  *                           4            14
00029  *      cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x
00030  *     where the remez error is
00031  *  
00032  *  |              2     4     6     8     10    12     14 |     -58
00033  *  |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x  +C6*x  )| <= 2
00034  *  |                                      | 
00035  * 
00036  *                 4     6     8     10    12     14 
00037  *  4. let r = C1*x +C2*x +C3*x +C4*x +C5*x  +C6*x  , then
00038  *         cos(x) = 1 - x*x/2 + r
00039  *     since cos(x+y) ~ cos(x) - sin(x)*y 
00040  *            ~ cos(x) - x*y,
00041  *     a correction term is necessary in cos(x) and hence
00042  *      cos(x+y) = 1 - (x*x/2 - (r - x*y))
00043  *     For better accuracy when x > 0.3, let qx = |x|/4 with
00044  *     the last 32 bits mask off, and if x > 0.78125, let qx = 0.28125.
00045  *     Then
00046  *      cos(x+y) = (1-qx) - ((x*x/2-qx) - (r-x*y)).
00047  *     Note that 1-qx and (x*x/2-qx) is EXACT here, and the
00048  *     magnitude of the latter is at least a quarter of x*x/2,
00049  *     thus, reducing the rounding error in the subtraction.
00050  */
00051 
00052 #include "math.h"
00053 #include "mathP.h"
00054 
00055 #ifdef __STDC__
00056 static const double 
00057 #else
00058 static double 
00059 #endif
00060 one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
00061 C1  =  4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */
00062 C2  = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */
00063 C3  =  2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */
00064 C4  = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */
00065 C5  =  2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */
00066 C6  = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */
00067 
00068 #ifdef __STDC__
00069     double __kernel_cos(double x, double y)
00070 #else
00071     double __kernel_cos(x, y)
00072     double x,y;
00073 #endif
00074 {
00075     double a,hz,z,r,qx;
00076     int32_t ix;
00077     GET_HIGH_WORD(ix,x);
00078     ix &= 0x7fffffff;           /* ix = |x|'s high word*/
00079     if(ix<0x3e400000) {         /* if x < 2**27 */
00080         if(((int)x)==0) return one;     /* generate inexact */
00081     }
00082     z  = x*x;
00083     r  = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6)))));
00084     if(ix < 0x3FD33333)             /* if |x| < 0.3 */ 
00085         return one - (0.5*z - (z*r - x*y));
00086     else {
00087         if(ix > 0x3fe90000) {       /* x > 0.78125 */
00088         qx = 0.28125;
00089         } else {
00090             INSERT_WORDS(qx,ix-0x00200000,0);   /* x/4 */
00091         }
00092         hz = 0.5*z-qx;
00093         a  = one-qx;
00094         return a - (hz - (z*r-x*y));
00095     }
00096 }

Generated on Tue Feb 2 17:46:05 2010 for RTAI API by  doxygen 1.4.7