sincos.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. /* sincos.c
  2. *
  3. * Circular sine and cosine of argument in degrees
  4. * Table lookup and interpolation algorithm
  5. *
  6. *
  7. *
  8. * SYNOPSIS:
  9. *
  10. * double x, sine, cosine, flg, sincos();
  11. *
  12. * sincos( x, &sine, &cosine, flg );
  13. *
  14. *
  15. *
  16. * DESCRIPTION:
  17. *
  18. * Returns both the sine and the cosine of the argument x.
  19. * Several different compile time options and minimax
  20. * approximations are supplied to permit tailoring the
  21. * tradeoff between computation speed and accuracy.
  22. *
  23. * Since range reduction is time consuming, the reduction
  24. * of x modulo 360 degrees is also made optional.
  25. *
  26. * sin(i) is internally tabulated for 0 <= i <= 90 degrees.
  27. * Approximation polynomials, ranging from linear interpolation
  28. * to cubics in (x-i)**2, compute the sine and cosine
  29. * of the residual x-i which is between -0.5 and +0.5 degree.
  30. * In the case of the high accuracy options, the residual
  31. * and the tabulated values are combined using the trigonometry
  32. * formulas for sin(A+B) and cos(A+B).
  33. *
  34. * Compile time options are supplied for 5, 11, or 17 decimal
  35. * relative accuracy (ACC5, ACC11, ACC17 respectively).
  36. * A subroutine flag argument "flg" chooses betwen this
  37. * accuracy and table lookup only (peak absolute error
  38. * = 0.0087).
  39. *
  40. * If the argument flg = 1, then the tabulated value is
  41. * returned for the nearest whole number of degrees. The
  42. * approximation polynomials are not computed. At
  43. * x = 0.5 deg, the absolute error is then sin(0.5) = 0.0087.
  44. *
  45. * An intermediate speed and precision can be obtained using
  46. * the compile time option LINTERP and flg = 1. This yields
  47. * a linear interpolation using a slope estimated from the sine
  48. * or cosine at the nearest integer argument. The peak absolute
  49. * error with this option is 3.8e-5. Relative error at small
  50. * angles is about 1e-5.
  51. *
  52. * If flg = 0, then the approximation polynomials are computed
  53. * and applied.
  54. *
  55. *
  56. *
  57. * SPEED:
  58. *
  59. * Relative speed comparisons follow for 6MHz IBM AT clone
  60. * and Microsoft C version 4.0. These figures include
  61. * software overhead of do loop and function calls.
  62. * Since system hardware and software vary widely, the
  63. * numbers should be taken as representative only.
  64. *
  65. * flg=0 flg=0 flg=1 flg=1
  66. * ACC11 ACC5 LINTERP Lookup only
  67. * In-line 8087 (/FPi)
  68. * sin(), cos() 1.0 1.0 1.0 1.0
  69. *
  70. * In-line 8087 (/FPi)
  71. * sincos() 1.1 1.4 1.9 3.0
  72. *
  73. * Software (/FPa)
  74. * sin(), cos() 0.19 0.19 0.19 0.19
  75. *
  76. * Software (/FPa)
  77. * sincos() 0.39 0.50 0.73 1.7
  78. *
  79. *
  80. *
  81. * ACCURACY:
  82. *
  83. * The accurate approximations are designed with a relative error
  84. * criterion. The absolute error is greatest at x = 0.5 degree.
  85. * It decreases from a local maximum at i+0.5 degrees to full
  86. * machine precision at each integer i degrees. With the
  87. * ACC5 option, the relative error of 6.3e-6 is equivalent to
  88. * an absolute angular error of 0.01 arc second in the argument
  89. * at x = i+0.5 degrees. For small angles < 0.5 deg, the ACC5
  90. * accuracy is 6.3e-6 (.00063%) of reading; i.e., the absolute
  91. * error decreases in proportion to the argument. This is true
  92. * for both the sine and cosine approximations, since the latter
  93. * is for the function 1 - cos(x).
  94. *
  95. * If absolute error is of most concern, use the compile time
  96. * option ABSERR to obtain an absolute error of 2.7e-8 for ACC5
  97. * precision. This is about half the absolute error of the
  98. * relative precision option. In this case the relative error
  99. * for small angles will increase to 9.5e-6 -- a reasonable
  100. * tradeoff.
  101. */
  102. #include <math.h>
  103. /* Define one of the following to be 1:
  104. */
  105. #define ACC5 1
  106. #define ACC11 0
  107. #define ACC17 0
  108. /* Option for linear interpolation when flg = 1
  109. */
  110. #define LINTERP 1
  111. /* Option for absolute error criterion
  112. */
  113. #define ABSERR 1
  114. /* Option to include modulo 360 function:
  115. */
  116. #define MOD360 0
  117. /*
  118. Cephes Math Library Release 2.1
  119. Copyright 1987 by Stephen L. Moshier
  120. Direct inquiries to 30 Frost Street, Cambridge, MA 02140
  121. */
  122. /* Table of sin(i degrees)
  123. * for 0 <= i <= 90
  124. */
  125. static double sintbl[92] = {
  126. 0.00000000000000000000E0,
  127. 1.74524064372835128194E-2,
  128. 3.48994967025009716460E-2,
  129. 5.23359562429438327221E-2,
  130. 6.97564737441253007760E-2,
  131. 8.71557427476581735581E-2,
  132. 1.04528463267653471400E-1,
  133. 1.21869343405147481113E-1,
  134. 1.39173100960065444112E-1,
  135. 1.56434465040230869010E-1,
  136. 1.73648177666930348852E-1,
  137. 1.90808995376544812405E-1,
  138. 2.07911690817759337102E-1,
  139. 2.24951054343864998051E-1,
  140. 2.41921895599667722560E-1,
  141. 2.58819045102520762349E-1,
  142. 2.75637355816999185650E-1,
  143. 2.92371704722736728097E-1,
  144. 3.09016994374947424102E-1,
  145. 3.25568154457156668714E-1,
  146. 3.42020143325668733044E-1,
  147. 3.58367949545300273484E-1,
  148. 3.74606593415912035415E-1,
  149. 3.90731128489273755062E-1,
  150. 4.06736643075800207754E-1,
  151. 4.22618261740699436187E-1,
  152. 4.38371146789077417453E-1,
  153. 4.53990499739546791560E-1,
  154. 4.69471562785890775959E-1,
  155. 4.84809620246337029075E-1,
  156. 5.00000000000000000000E-1,
  157. 5.15038074910054210082E-1,
  158. 5.29919264233204954047E-1,
  159. 5.44639035015027082224E-1,
  160. 5.59192903470746830160E-1,
  161. 5.73576436351046096108E-1,
  162. 5.87785252292473129169E-1,
  163. 6.01815023152048279918E-1,
  164. 6.15661475325658279669E-1,
  165. 6.29320391049837452706E-1,
  166. 6.42787609686539326323E-1,
  167. 6.56059028990507284782E-1,
  168. 6.69130606358858213826E-1,
  169. 6.81998360062498500442E-1,
  170. 6.94658370458997286656E-1,
  171. 7.07106781186547524401E-1,
  172. 7.19339800338651139356E-1,
  173. 7.31353701619170483288E-1,
  174. 7.43144825477394235015E-1,
  175. 7.54709580222771997943E-1,
  176. 7.66044443118978035202E-1,
  177. 7.77145961456970879980E-1,
  178. 7.88010753606721956694E-1,
  179. 7.98635510047292846284E-1,
  180. 8.09016994374947424102E-1,
  181. 8.19152044288991789684E-1,
  182. 8.29037572555041692006E-1,
  183. 8.38670567945424029638E-1,
  184. 8.48048096156425970386E-1,
  185. 8.57167300702112287465E-1,
  186. 8.66025403784438646764E-1,
  187. 8.74619707139395800285E-1,
  188. 8.82947592858926942032E-1,
  189. 8.91006524188367862360E-1,
  190. 8.98794046299166992782E-1,
  191. 9.06307787036649963243E-1,
  192. 9.13545457642600895502E-1,
  193. 9.20504853452440327397E-1,
  194. 9.27183854566787400806E-1,
  195. 9.33580426497201748990E-1,
  196. 9.39692620785908384054E-1,
  197. 9.45518575599316810348E-1,
  198. 9.51056516295153572116E-1,
  199. 9.56304755963035481339E-1,
  200. 9.61261695938318861916E-1,
  201. 9.65925826289068286750E-1,
  202. 9.70295726275996472306E-1,
  203. 9.74370064785235228540E-1,
  204. 9.78147600733805637929E-1,
  205. 9.81627183447663953497E-1,
  206. 9.84807753012208059367E-1,
  207. 9.87688340595137726190E-1,
  208. 9.90268068741570315084E-1,
  209. 9.92546151641322034980E-1,
  210. 9.94521895368273336923E-1,
  211. 9.96194698091745532295E-1,
  212. 9.97564050259824247613E-1,
  213. 9.98629534754573873784E-1,
  214. 9.99390827019095730006E-1,
  215. 9.99847695156391239157E-1,
  216. 1.00000000000000000000E0,
  217. 9.99847695156391239157E-1,
  218. };
  219. #ifdef ANSIPROT
  220. double floor ( double );
  221. #else
  222. double floor();
  223. #endif
  224. int sincos(x, s, c, flg)
  225. double x;
  226. double *s, *c;
  227. int flg;
  228. {
  229. int ix, ssign, csign, xsign;
  230. double y, z, sx, sz, cx, cz;
  231. /* Make argument nonnegative.
  232. */
  233. xsign = 1;
  234. if( x < 0.0 )
  235. {
  236. xsign = -1;
  237. x = -x;
  238. }
  239. #if MOD360
  240. x = x - 360.0 * floor( x/360.0 );
  241. #endif
  242. /* Find nearest integer to x.
  243. * Note there should be a domain error test here,
  244. * but this is omitted to gain speed.
  245. */
  246. ix = x + 0.5;
  247. z = x - ix; /* the residual */
  248. /* Look up the sine and cosine of the integer.
  249. */
  250. if( ix <= 180 )
  251. {
  252. ssign = 1;
  253. csign = 1;
  254. }
  255. else
  256. {
  257. ssign = -1;
  258. csign = -1;
  259. ix -= 180;
  260. }
  261. if( ix > 90 )
  262. {
  263. csign = -csign;
  264. ix = 180 - ix;
  265. }
  266. sx = sintbl[ix];
  267. if( ssign < 0 )
  268. sx = -sx;
  269. cx = sintbl[ 90-ix ];
  270. if( csign < 0 )
  271. cx = -cx;
  272. /* If the flag argument is set, then just return
  273. * the tabulated values for arg to the nearest whole degree.
  274. */
  275. if( flg )
  276. {
  277. #if LINTERP
  278. y = sx + 1.74531263774940077459e-2 * z * cx;
  279. cx -= 1.74531263774940077459e-2 * z * sx;
  280. sx = y;
  281. #endif
  282. if( xsign < 0 )
  283. sx = -sx;
  284. *s = sx; /* sine */
  285. *c = cx; /* cosine */
  286. return 0;
  287. }
  288. if( ssign < 0 )
  289. sx = -sx;
  290. if( csign < 0 )
  291. cx = -cx;
  292. /* Find sine and cosine
  293. * of the residual angle between -0.5 and +0.5 degree.
  294. */
  295. #if ACC5
  296. #if ABSERR
  297. /* absolute error = 2.769e-8: */
  298. sz = 1.74531263774940077459e-2 * z;
  299. /* absolute error = 4.146e-11: */
  300. cz = 1.0 - 1.52307909153324666207e-4 * z * z;
  301. #else
  302. /* relative error = 6.346e-6: */
  303. sz = 1.74531817576426662296e-2 * z;
  304. /* relative error = 3.173e-6: */
  305. cz = 1.0 - 1.52308226602566149927e-4 * z * z;
  306. #endif
  307. #else
  308. y = z * z;
  309. #endif
  310. #if ACC11
  311. sz = ( -8.86092781698004819918e-7 * y
  312. + 1.74532925198378577601e-2 ) * z;
  313. cz = 1.0 - ( -3.86631403698859047896e-9 * y
  314. + 1.52308709893047593702e-4 ) * y;
  315. #endif
  316. #if ACC17
  317. sz = (( 1.34959795251974073996e-11 * y
  318. - 8.86096155697856783296e-7 ) * y
  319. + 1.74532925199432957214e-2 ) * z;
  320. cz = 1.0 - (( 3.92582397764340914444e-14 * y
  321. - 3.86632385155548605680e-9 ) * y
  322. + 1.52308709893354299569e-4 ) * y;
  323. #endif
  324. /* Combine the tabulated part and the calculated part
  325. * by trigonometry.
  326. */
  327. y = sx * cz + cx * sz;
  328. if( xsign < 0 )
  329. y = - y;
  330. *s = y; /* sine */
  331. *c = cx * cz - sx * sz; /* cosine */
  332. return 0;
  333. }