sincos.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. // Copyright 2011 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package math32
  5. import "math/bits"
  6. /*
  7. Floating-point sine and cosine.
  8. */
  9. // The original C code, the long comment, and the constants
  10. // below were from http://netlib.sandia.gov/cephes/cmath/sin.c,
  11. // available from http://www.netlib.org/cephes/cmath.tgz.
  12. // The go code is a simplified version of the original C.
  13. //
  14. // sin.c
  15. //
  16. // Circular sine
  17. //
  18. // SYNOPSIS:
  19. //
  20. // double x, y, sin();
  21. // y = sin( x );
  22. //
  23. // DESCRIPTION:
  24. //
  25. // Range reduction is into intervals of pi/4. The reduction error is nearly
  26. // eliminated by contriving an extended precision modular arithmetic.
  27. //
  28. // Two polynomial approximating functions are employed.
  29. // Between 0 and pi/4 the sine is approximated by
  30. // x + x**3 P(x**2).
  31. // Between pi/4 and pi/2 the cosine is represented as
  32. // 1 - x**2 Q(x**2).
  33. //
  34. // ACCURACY:
  35. //
  36. // Relative error:
  37. // arithmetic domain # trials peak rms
  38. // DEC 0, 10 150000 3.0e-17 7.8e-18
  39. // IEEE -1.07e9,+1.07e9 130000 2.1e-16 5.4e-17
  40. //
  41. // Partial loss of accuracy begins to occur at x = 2**30 = 1.074e9. The loss
  42. // is not gradual, but jumps suddenly to about 1 part in 10e7. Results may
  43. // be meaningless for x > 2**49 = 5.6e14.
  44. //
  45. // cos.c
  46. //
  47. // Circular cosine
  48. //
  49. // SYNOPSIS:
  50. //
  51. // double x, y, cos();
  52. // y = cos( x );
  53. //
  54. // DESCRIPTION:
  55. //
  56. // Range reduction is into intervals of pi/4. The reduction error is nearly
  57. // eliminated by contriving an extended precision modular arithmetic.
  58. //
  59. // Two polynomial approximating functions are employed.
  60. // Between 0 and pi/4 the cosine is approximated by
  61. // 1 - x**2 Q(x**2).
  62. // Between pi/4 and pi/2 the sine is represented as
  63. // x + x**3 P(x**2).
  64. //
  65. // ACCURACY:
  66. //
  67. // Relative error:
  68. // arithmetic domain # trials peak rms
  69. // IEEE -1.07e9,+1.07e9 130000 2.1e-16 5.4e-17
  70. // DEC 0,+1.07e9 17000 3.0e-17 7.2e-18
  71. //
  72. // Cephes Math Library Release 2.8: June, 2000
  73. // Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
  74. //
  75. // The readme file at http://netlib.sandia.gov/cephes/ says:
  76. // Some software in this archive may be from the book _Methods and
  77. // Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
  78. // International, 1989) or from the Cephes Mathematical Library, a
  79. // commercial product. In either event, it is copyrighted by the author.
  80. // What you see here may be used freely but it comes with no support or
  81. // guarantee.
  82. //
  83. // The two known misprints in the book are repaired here in the
  84. // source listings for the gamma function and the incomplete beta
  85. // integral.
  86. //
  87. // Stephen L. Moshier
  88. // moshier@na-net.ornl.gov
  89. // sin coefficients
  90. var _sin = [...]float32{
  91. 1.58962301576546568060e-10, // 0x3de5d8fd1fd19ccd
  92. -2.50507477628578072866e-8, // 0xbe5ae5e5a9291f5d
  93. 2.75573136213857245213e-6, // 0x3ec71de3567d48a1
  94. -1.98412698295895385996e-4, // 0xbf2a01a019bfdf03
  95. 8.33333333332211858878e-3, // 0x3f8111111110f7d0
  96. -1.66666666666666307295e-1, // 0xbfc5555555555548
  97. }
  98. // cos coefficients
  99. var _cos = [...]float32{
  100. -1.13585365213876817300e-11, // 0xbda8fa49a0861a9b
  101. 2.08757008419747316778e-9, // 0x3e21ee9d7b4e3f05
  102. -2.75573141792967388112e-7, // 0xbe927e4f7eac4bc6
  103. 2.48015872888517045348e-5, // 0x3efa01a019c844f5
  104. -1.38888888888730564116e-3, // 0xbf56c16c16c14f91
  105. 4.16666666666665929218e-2, // 0x3fa555555555554b
  106. }
  107. // Sincos returns Sin(x), Cos(x).
  108. //
  109. // Special cases are:
  110. // Sincos(±0) = ±0, 1
  111. // Sincos(±Inf) = NaN, NaN
  112. // Sincos(NaN) = NaN, NaN
  113. func Sincos(x float32) (sin, cos float32) {
  114. const (
  115. PI4A = 7.85398125648498535156e-1 // 0x3fe921fb40000000, Pi/4 split into three parts
  116. PI4B = 3.77489470793079817668e-8 // 0x3e64442d00000000,
  117. PI4C = 2.69515142907905952645e-15 // 0x3ce8469898cc5170,
  118. )
  119. // special cases
  120. switch {
  121. case x == 0:
  122. return x, 1 // return ±0.0, 1.0
  123. case IsNaN(x) || IsInf(x, 0):
  124. return NaN(), NaN()
  125. }
  126. // make argument positive
  127. sinSign, cosSign := false, false
  128. if x < 0 {
  129. x = -x
  130. sinSign = true
  131. }
  132. var j uint64
  133. var y, z float32
  134. if x >= reduceThreshold {
  135. j, z = trigReduce(x)
  136. } else {
  137. j = uint64(x * (4 / Pi)) // integer part of x/(Pi/4), as integer for tests on the phase angle
  138. y = float32(j) // integer part of x/(Pi/4), as float
  139. if j&1 == 1 { // map zeros to origin
  140. j++
  141. y++
  142. }
  143. j &= 7 // octant modulo 2Pi radians (360 degrees)
  144. z = ((x - y*PI4A) - y*PI4B) - y*PI4C // Extended precision modular arithmetic
  145. }
  146. if j > 3 { // reflect in x axis
  147. j -= 4
  148. sinSign, cosSign = !sinSign, !cosSign
  149. }
  150. if j > 1 {
  151. cosSign = !cosSign
  152. }
  153. zz := z * z
  154. cos = 1.0 - 0.5*zz + zz*zz*((((((_cos[0]*zz)+_cos[1])*zz+_cos[2])*zz+_cos[3])*zz+_cos[4])*zz+_cos[5])
  155. sin = z + z*zz*((((((_sin[0]*zz)+_sin[1])*zz+_sin[2])*zz+_sin[3])*zz+_sin[4])*zz+_sin[5])
  156. if j == 1 || j == 2 {
  157. sin, cos = cos, sin
  158. }
  159. if cosSign {
  160. cos = -cos
  161. }
  162. if sinSign {
  163. sin = -sin
  164. }
  165. return
  166. }
  167. // Sin returns the sine of the radian argument x.
  168. //
  169. // Special cases are:
  170. // Sin(±0) = ±0
  171. // Sin(±Inf) = NaN
  172. // Sin(NaN) = NaN
  173. func Sin(x float32) float32 {
  174. const (
  175. PI4A = 7.85398125648498535156e-1 // 0x3fe921fb40000000, Pi/4 split into three parts
  176. PI4B = 3.77489470793079817668e-8 // 0x3e64442d00000000,
  177. PI4C = 2.69515142907905952645e-15 // 0x3ce8469898cc5170,
  178. )
  179. // special cases
  180. switch {
  181. case x == 0 || IsNaN(x):
  182. return x // return ±0 || NaN()
  183. case IsInf(x, 0):
  184. return NaN()
  185. }
  186. // make argument positive but save the sign
  187. sign := false
  188. if x < 0 {
  189. x = -x
  190. sign = true
  191. }
  192. var j uint64
  193. var y, z float32
  194. if x >= reduceThreshold {
  195. j, z = trigReduce(x)
  196. } else {
  197. j = uint64(x * (4 / Pi)) // integer part of x/(Pi/4), as integer for tests on the phase angle
  198. y = float32(j) // integer part of x/(Pi/4), as float
  199. // map zeros to origin
  200. if j&1 == 1 {
  201. j++
  202. y++
  203. }
  204. j &= 7 // octant modulo 2Pi radians (360 degrees)
  205. z = ((x - y*PI4A) - y*PI4B) - y*PI4C // Extended precision modular arithmetic
  206. }
  207. // reflect in x axis
  208. if j > 3 {
  209. sign = !sign
  210. j -= 4
  211. }
  212. zz := z * z
  213. if j == 1 || j == 2 {
  214. y = 1.0 - 0.5*zz + zz*zz*((((((_cos[0]*zz)+_cos[1])*zz+_cos[2])*zz+_cos[3])*zz+_cos[4])*zz+_cos[5])
  215. } else {
  216. y = z + z*zz*((((((_sin[0]*zz)+_sin[1])*zz+_sin[2])*zz+_sin[3])*zz+_sin[4])*zz+_sin[5])
  217. }
  218. if sign {
  219. y = -y
  220. }
  221. return y
  222. }
  223. // Cos returns the cosine of the radian argument x.
  224. //
  225. // Special cases are:
  226. // Cos(±Inf) = NaN
  227. // Cos(NaN) = NaN
  228. func Cos(x float32) float32 {
  229. const (
  230. PI4A = 7.85398125648498535156e-1 // 0x3fe921fb40000000, Pi/4 split into three parts
  231. PI4B = 3.77489470793079817668e-8 // 0x3e64442d00000000,
  232. PI4C = 2.69515142907905952645e-15 // 0x3ce8469898cc5170,
  233. )
  234. // special cases
  235. switch {
  236. case IsNaN(x) || IsInf(x, 0):
  237. return NaN()
  238. }
  239. // make argument positive
  240. sign := false
  241. x = Abs(x)
  242. var j uint64
  243. var y, z float32
  244. if x >= reduceThreshold {
  245. j, z = trigReduce(x)
  246. } else {
  247. j = uint64(x * (4 / Pi)) // integer part of x/(Pi/4), as integer for tests on the phase angle
  248. y = float32(j) // integer part of x/(Pi/4), as float
  249. // map zeros to origin
  250. if j&1 == 1 {
  251. j++
  252. y++
  253. }
  254. j &= 7 // octant modulo 2Pi radians (360 degrees)
  255. z = ((x - y*PI4A) - y*PI4B) - y*PI4C // Extended precision modular arithmetic
  256. }
  257. if j > 3 {
  258. j -= 4
  259. sign = !sign
  260. }
  261. if j > 1 {
  262. sign = !sign
  263. }
  264. zz := z * z
  265. if j == 1 || j == 2 {
  266. y = z + z*zz*((((((_sin[0]*zz)+_sin[1])*zz+_sin[2])*zz+_sin[3])*zz+_sin[4])*zz+_sin[5])
  267. } else {
  268. y = 1.0 - 0.5*zz + zz*zz*((((((_cos[0]*zz)+_cos[1])*zz+_cos[2])*zz+_cos[3])*zz+_cos[4])*zz+_cos[5])
  269. }
  270. if sign {
  271. y = -y
  272. }
  273. return y
  274. }
  275. // reduceThreshold is the maximum value of x where the reduction using Pi/4
  276. // in 3 float64 parts still gives accurate results. This threshold
  277. // is set by y*C being representable as a float64 without error
  278. // where y is given by y = floor(x * (4 / Pi)) and C is the leading partial
  279. // terms of 4/Pi. Since the leading terms (PI4A and PI4B in sin.go) have 30
  280. // and 32 trailing zero bits, y should have less than 30 significant bits.
  281. // y < 1<<30 -> floor(x*4/Pi) < 1<<30 -> x < (1<<30 - 1) * Pi/4
  282. // So, conservatively we can take x < 1<<29.
  283. // Above this threshold Payne-Hanek range reduction must be used.
  284. const reduceThreshold = 1 << 29
  285. // trigReduce implements Payne-Hanek range reduction by Pi/4
  286. // for x > 0. It returns the integer part mod 8 (j) and
  287. // the fractional part (z) of x / (Pi/4).
  288. // The implementation is based on:
  289. // "ARGUMENT REDUCTION FOR HUGE ARGUMENTS: Good to the Last Bit"
  290. // K. C. Ng et al, March 24, 1992
  291. // The simulated multi-precision calculation of x*B uses 64-bit integer arithmetic.
  292. func trigReduce(x float32) (j uint64, z float32) {
  293. const PI4 = Pi / 4
  294. if x < PI4 {
  295. return 0, x
  296. }
  297. // Extract out the integer and exponent such that,
  298. // x = ix * 2 ** exp.
  299. ix := Float32bits(x)
  300. exp := int(ix>>shift&mask) - bias - shift
  301. ix &^= mask << shift
  302. ix |= 1 << shift
  303. // Use the exponent to extract the 3 appropriate uint64 digits from mPi4,
  304. // B ~ (z0, z1, z2), such that the product leading digit has the exponent -61.
  305. // Note, exp >= -53 since x >= PI4 and exp < 971 for maximum float64.
  306. const floatingbits = 32 - 3
  307. digit, bitshift := uint(exp+floatingbits)/32, uint(exp+floatingbits)%32
  308. z0 := (mPi4[digit] << bitshift) | (mPi4[digit+1] >> (32 - bitshift))
  309. z1 := (mPi4[digit+1] << bitshift) | (mPi4[digit+2] >> (32 - bitshift))
  310. z2 := (mPi4[digit+2] << bitshift) | (mPi4[digit+3] >> (32 - bitshift))
  311. // Multiply mantissa by the digits and extract the upper two digits (hi, lo).
  312. z2hi, _ := bits.Mul64(z2, uint64(ix))
  313. z1hi, z1lo := bits.Mul64(z1, uint64(ix))
  314. z0lo := z0 * uint64(ix)
  315. lo, c := bits.Add64(z1lo, z2hi, 0)
  316. hi, _ := bits.Add64(z0lo, z1hi, c)
  317. // The top 3 bits are j.
  318. j = hi >> floatingbits
  319. // Extract the fraction and find its magnitude.
  320. hi = hi<<3 | lo>>floatingbits
  321. lz := uint(bits.LeadingZeros64(hi))
  322. e := uint64(bias - (lz + 1))
  323. // Clear implicit mantissa bit and shift into place.
  324. hi = (hi << (lz + 1)) | (lo >> (32 - (lz + 1)))
  325. hi >>= 43 - shift
  326. // Include the exponent and convert to a float.
  327. hi |= e << shift
  328. z = Float32frombits(uint32(hi))
  329. // Map zeros to origin.
  330. if j&1 == 1 {
  331. j++
  332. j &= 7
  333. z--
  334. }
  335. // Multiply the fractional part by pi/4.
  336. return j, z * PI4
  337. }
  338. // mPi4 is the binary digits of 4/pi as a uint64 array,
  339. // that is, 4/pi = Sum mPi4[i]*2^(-64*i)
  340. // 19 64-bit digits and the leading one bit give 1217 bits
  341. // of precision to handle the largest possible float64 exponent.
  342. var mPi4 = [...]uint64{
  343. 0x0000000000000001,
  344. 0x45f306dc9c882a53,
  345. 0xf84eafa3ea69bb81,
  346. 0xb6c52b3278872083,
  347. 0xfca2c757bd778ac3,
  348. 0x6e48dc74849ba5c0,
  349. 0x0c925dd413a32439,
  350. 0xfc3bd63962534e7d,
  351. 0xd1046bea5d768909,
  352. 0xd338e04d68befc82,
  353. 0x7323ac7306a673e9,
  354. 0x3908bf177bf25076,
  355. 0x3ff12fffbc0b301f,
  356. 0xde5e2316b414da3e,
  357. 0xda6cfd9e4f96136e,
  358. 0x9e8c7ecd3cbfd45a,
  359. 0xea4f758fd7cbe2f6,
  360. 0x7a0e73ef14a525d4,
  361. 0xd7f6bf623f1aba10,
  362. 0xac06608df8f6d757,
  363. }