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