123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- /* Program to test range reduction of trigonometry functions
- *
- * -- Steve Moshier
- */
- #include <math.h>
- #ifdef ANSIPROT
- extern double floor ( double );
- extern double ldexp ( double, int );
- extern double sin ( double );
- #else
- double floor(), ldexp(), sin();
- #endif
- #define TPI 6.283185307179586476925
- main()
- {
- char s[40];
- double a, n, t, x, y, z;
- int lflg;
- x = TPI/4.0;
- t = 1.0;
- loop:
- t = 2.0 * t;
- /* Stop testing at a point beyond which the integer part of
- * x/2pi cannot be represented exactly by a double precision number.
- * The library trigonometry functions will probably give up long before
- * this point is reached.
- */
- if( t > 1.0e16 )
- exit(0);
- /* Adjust the following to choose a nontrivial x
- * where test function(x) has a slope of about 1 or more.
- */
- x = TPI * t + 0.5;
- z = x;
- lflg = 0;
- inlup:
- /* floor() returns the largest integer less than its argument.
- * If you do not have this, or AINT(), then you may convert x/TPI
- * to a long integer and then back to double; but in that case
- * x will be limited to the largest value that will fit into a
- * long integer.
- */
- n = floor( z/TPI );
- /* Carefully subtract 2 pi n from x.
- * This is done by subtracting n * 2**k in such a way that there
- * is no arithmetic cancellation error at any step. The k are the
- * bits in the number 2 pi.
- *
- * If you do not have ldexp(), then you may multiply or
- * divide n by an appropriate power of 2 after each step.
- * For example:
- * a = z - 4*n;
- * a -= 2*n;
- * n /= 4;
- * a -= n; n/4
- * n /= 8;
- * a -= n; n/32
- * etc.
- * This will only work if division by a power of 2 is exact.
- */
- a = z - ldexp(n, 2); /* 4n */
- a -= ldexp( n, 1); /* 2n */
- a -= ldexp( n, -2 ); /* n/4 */
- a -= ldexp( n, -5 ); /* n/32 */
- a -= ldexp( n, -9 ); /* n/512 */
- a += ldexp( n, -15 ); /* add n/32768 */
- a -= ldexp( n, -17 ); /* n/131072 */
- a -= ldexp( n, -18 );
- a -= ldexp( n, -20 );
- a -= ldexp( n, -22 );
- a -= ldexp( n, -24 );
- a -= ldexp( n, -28 );
- a -= ldexp( n, -32 );
- a -= ldexp( n, -37 );
- a -= ldexp( n, -39 );
- a -= ldexp( n, -40 );
- a -= ldexp( n, -42 );
- a -= ldexp( n, -46 );
- a -= ldexp( n, -47 );
- /* Subtract what is left of 2 pi n after all the above reductions.
- */
- a -= 2.44929359829470635445e-16 * n;
- /* If the test is extended too far, it is possible
- * to have chosen the wrong value of n. The following
- * will fix that, but at some reduction in accuracy.
- */
- if( (a > TPI) || (a < -1e-11) )
- {
- z = a;
- lflg += 1;
- printf( "Warning! Reduction failed on first try.\n" );
- goto inlup;
- }
- if( a < 0.0 )
- {
- printf( "Warning! Reduced value < 0\n" );
- a += TPI;
- }
- /* Compute the test function at x and at a = x mod 2 pi.
- */
- y = sin(x);
- z = sin(a);
- printf( "sin(%.15e) error = %.3e\n", x, y-z );
- goto loop;
- }
|