Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

241 lines
5.8 KiB

  1. /***
  2. *sincos.c - sine and cosine
  3. *
  4. * Copyright (c) 1991-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *
  8. *Revision History:
  9. * 8-15-91 GDP written
  10. * 9-29-91 GDP added missing ABS() for cosine
  11. * 12-26-91 GDP IEEE exceptions support
  12. * 03-11-91 GDP use 66 significant bits for representing pi
  13. * support FP_TLOSS, use _frnd for rounding
  14. * 06-23-92 GDP sin(denormal) now raises underflow exception
  15. * 02-06-95 JWM Mac merge
  16. * 10-07-97 RDL Added IA64.
  17. *
  18. *******************************************************************************/
  19. #include <math.h>
  20. #include <trans.h>
  21. #if defined(_M_IA64)
  22. #pragma function(sin, cos)
  23. #endif
  24. static double _sincos(double x, double y, double sin);
  25. /* constants */
  26. static double const EPS = 1.05367121277235079465e-8; /* 2^(-53/2) */
  27. static double const PI = 3.14159265358979323846;
  28. static double const PI2 = 1.57079632679489661923; /* pi/2 */
  29. static double const PI_INV = 0.31830988618379067154; /* 1/pi */
  30. static double const YMAX = 2.2e8; /* approx. pi * 2 ^(t/2), where t=53 */
  31. //
  32. // The sum of C1 and C2 is a representation of PI with 66 bits in the
  33. // significand (same as x87). (PI = 4 * 0.c90fdaa2 2168c234 c h)
  34. //
  35. static _dbl _C1 = {SET_DBL (0x400921fb, 0x54400000)};
  36. static _dbl _C2 = {SET_DBL (0x3de0b461, 0x1a600000)};
  37. #define C1 (_C1.dbl)
  38. #define C2 (_C2.dbl)
  39. /* constants for the polynomial approximation of sin, cos */
  40. static double const r1 = -0.16666666666666665052e+0;
  41. static double const r2 = 0.83333333333331650314e-2;
  42. static double const r3 = -0.19841269841201840457e-3;
  43. static double const r4 = 0.27557319210152756119e-5;
  44. static double const r5 = -0.25052106798274584544e-7;
  45. static double const r6 = 0.16058936490371589114e-9;
  46. static double const r7 = -0.76429178068910467734e-12;
  47. static double const r8 = 0.27204790957888846175e-14;
  48. #define R(g) ((((((((r8 * (g) + r7) * (g) + r6) * (g) + r5) * (g) + r4) \
  49. * (g) + r3) * (g) + r2) * (g) + r1) * (g))
  50. /***
  51. *double sin(double x) - sine
  52. *
  53. *Purpose:
  54. * Compute the sine of a number.
  55. * The algorithm (reduction / polynomial approximation) is
  56. * taken from Cody & Waite.
  57. *
  58. *Entry:
  59. *
  60. *Exit:
  61. *
  62. *Exceptions:
  63. * I, P, U
  64. * if x is denormal: raise Underflow
  65. *******************************************************************************/
  66. double sin (double x)
  67. {
  68. uintptr_t savedcw;
  69. double result;
  70. double sign,y;
  71. /* save user fp control word */
  72. savedcw = _maskfp();
  73. if (IS_D_SPECIAL(x)){
  74. switch(_sptype(x)) {
  75. case T_PINF:
  76. case T_NINF:
  77. return _except1(FP_I,OP_SIN,x,QNAN_SIN1,savedcw);
  78. case T_QNAN:
  79. return _handle_qnan1(OP_SIN, x, savedcw);
  80. default: //T_SNAN
  81. return _except1(FP_I,OP_SIN,x,_s2qnan(x),savedcw);
  82. }
  83. }
  84. if (x == 0.0) {
  85. // no P exception
  86. RETURN(savedcw,x);
  87. }
  88. if (x < 0) {
  89. sign = -1;
  90. y = -x;
  91. }
  92. else {
  93. sign = 1;
  94. y = x;
  95. }
  96. if (y >= YMAX) {
  97. // The argument is too large to produce a meaningful result,
  98. // so this is treated as an invalid operation.
  99. // We also set the (extra) FP_TLOSS flag for matherr
  100. // support
  101. return _except1(FP_TLOSS | FP_I,OP_SIN,x,QNAN_SIN2,savedcw);
  102. }
  103. result = _sincos(x,y,sign);
  104. if (IS_D_DENORM(result)) {
  105. return _except1(FP_U | FP_P,OP_SIN,x,_add_exp(result, IEEE_ADJUST),savedcw);
  106. }
  107. RETURN_INEXACT1(OP_SIN,x,result,savedcw);
  108. }
  109. /***
  110. *double cos(double x) - cosine
  111. *
  112. *Purpose:
  113. * Compute the cosine of a number.
  114. * The algorithm (reduction / polynomial approximation) is
  115. * taken from Cody & Waite.
  116. *
  117. *Entry:
  118. *
  119. *Exit:
  120. *
  121. *Exceptions:
  122. * P, I
  123. * if x is denormal: return 1
  124. *******************************************************************************/
  125. double cos (double x)
  126. {
  127. uintptr_t savedcw;
  128. double result,y;
  129. /* save user fp control word */
  130. savedcw = _maskfp();
  131. if (IS_D_SPECIAL(x)){
  132. switch(_sptype(x)) {
  133. case T_PINF:
  134. case T_NINF:
  135. return _except1(FP_I,OP_COS,x,QNAN_COS1,savedcw);
  136. case T_QNAN:
  137. return _handle_qnan1(OP_COS,x, savedcw);
  138. default: //T_SNAN
  139. return _except1(FP_I,OP_COS,x,_s2qnan(x),savedcw);
  140. }
  141. }
  142. /* this will handle small arguments */
  143. if (ABS(x) < EPS) {
  144. if (x == 0.0) {
  145. RETURN(savedcw,1.0);
  146. }
  147. result = 1.0;
  148. }
  149. else {
  150. y = ABS(x) + PI2;
  151. if (y >= YMAX) {
  152. // The argument is too large to produce a meaningful result,
  153. // so this is treated as an invalid operation.
  154. // We also set the (extra) FP_TLOSS flag for matherr
  155. // support
  156. return _except1(FP_TLOSS | FP_I,OP_COS,x,QNAN_COS2,savedcw);
  157. }
  158. result = _sincos(x,y,1.0);
  159. }
  160. RETURN_INEXACT1(OP_COS,x,result,savedcw);
  161. }
  162. /***
  163. *double _sincos(double x, double y,double sign) - cos sin helper
  164. *
  165. *Purpose:
  166. * Help computing sin or cos of a valid, within correct range
  167. * number.
  168. * The algorithm (reduction / polynomial approximation) is
  169. * taken from Cody & Waite.
  170. *
  171. *Entry:
  172. *
  173. *Exit:
  174. *
  175. *Exceptions:
  176. *
  177. *******************************************************************************/
  178. static double _sincos(double x, double y, double sign)
  179. {
  180. unsigned long n;
  181. double xn,f,g,r,result;
  182. xn = _frnd(y * PI_INV);
  183. n = (int) xn;
  184. if (n & 0x1) {
  185. /* n is odd */
  186. sign = -sign;
  187. }
  188. if (ABS(x) != y) {
  189. /* cosine wanted */
  190. xn -= .5;
  191. }
  192. /* assume there is a guard digit for addition */
  193. f = (ABS(x) - xn * C1) - xn * C2;
  194. if (ABS(f) < EPS)
  195. result = f;
  196. else {
  197. g = f*f;
  198. r = R(g);
  199. result = f + f*r;
  200. }
  201. result *= sign;
  202. return result;
  203. }