mod2pi.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. /* Program to test range reduction of trigonometry functions
  2. *
  3. * -- Steve Moshier
  4. */
  5. #include <math.h>
  6. #ifdef ANSIPROT
  7. extern double floor ( double );
  8. extern double ldexp ( double, int );
  9. extern double sin ( double );
  10. #else
  11. double floor(), ldexp(), sin();
  12. #endif
  13. #define TPI 6.283185307179586476925
  14. main()
  15. {
  16. char s[40];
  17. double a, n, t, x, y, z;
  18. int lflg;
  19. x = TPI/4.0;
  20. t = 1.0;
  21. loop:
  22. t = 2.0 * t;
  23. /* Stop testing at a point beyond which the integer part of
  24. * x/2pi cannot be represented exactly by a double precision number.
  25. * The library trigonometry functions will probably give up long before
  26. * this point is reached.
  27. */
  28. if( t > 1.0e16 )
  29. exit(0);
  30. /* Adjust the following to choose a nontrivial x
  31. * where test function(x) has a slope of about 1 or more.
  32. */
  33. x = TPI * t + 0.5;
  34. z = x;
  35. lflg = 0;
  36. inlup:
  37. /* floor() returns the largest integer less than its argument.
  38. * If you do not have this, or AINT(), then you may convert x/TPI
  39. * to a long integer and then back to double; but in that case
  40. * x will be limited to the largest value that will fit into a
  41. * long integer.
  42. */
  43. n = floor( z/TPI );
  44. /* Carefully subtract 2 pi n from x.
  45. * This is done by subtracting n * 2**k in such a way that there
  46. * is no arithmetic cancellation error at any step. The k are the
  47. * bits in the number 2 pi.
  48. *
  49. * If you do not have ldexp(), then you may multiply or
  50. * divide n by an appropriate power of 2 after each step.
  51. * For example:
  52. * a = z - 4*n;
  53. * a -= 2*n;
  54. * n /= 4;
  55. * a -= n; n/4
  56. * n /= 8;
  57. * a -= n; n/32
  58. * etc.
  59. * This will only work if division by a power of 2 is exact.
  60. */
  61. a = z - ldexp(n, 2); /* 4n */
  62. a -= ldexp( n, 1); /* 2n */
  63. a -= ldexp( n, -2 ); /* n/4 */
  64. a -= ldexp( n, -5 ); /* n/32 */
  65. a -= ldexp( n, -9 ); /* n/512 */
  66. a += ldexp( n, -15 ); /* add n/32768 */
  67. a -= ldexp( n, -17 ); /* n/131072 */
  68. a -= ldexp( n, -18 );
  69. a -= ldexp( n, -20 );
  70. a -= ldexp( n, -22 );
  71. a -= ldexp( n, -24 );
  72. a -= ldexp( n, -28 );
  73. a -= ldexp( n, -32 );
  74. a -= ldexp( n, -37 );
  75. a -= ldexp( n, -39 );
  76. a -= ldexp( n, -40 );
  77. a -= ldexp( n, -42 );
  78. a -= ldexp( n, -46 );
  79. a -= ldexp( n, -47 );
  80. /* Subtract what is left of 2 pi n after all the above reductions.
  81. */
  82. a -= 2.44929359829470635445e-16 * n;
  83. /* If the test is extended too far, it is possible
  84. * to have chosen the wrong value of n. The following
  85. * will fix that, but at some reduction in accuracy.
  86. */
  87. if( (a > TPI) || (a < -1e-11) )
  88. {
  89. z = a;
  90. lflg += 1;
  91. printf( "Warning! Reduction failed on first try.\n" );
  92. goto inlup;
  93. }
  94. if( a < 0.0 )
  95. {
  96. printf( "Warning! Reduced value < 0\n" );
  97. a += TPI;
  98. }
  99. /* Compute the test function at x and at a = x mod 2 pi.
  100. */
  101. y = sin(x);
  102. z = sin(a);
  103. printf( "sin(%.15e) error = %.3e\n", x, y-z );
  104. goto loop;
  105. }