...

Source file src/math/sin.go

Documentation: math

		 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 math
		 6  
		 7  /*
		 8  	Floating-point sine and cosine.
		 9  */
		10  
		11  // The original C code, the long comment, and the constants
		12  // below were from http://netlib.sandia.gov/cephes/cmath/sin.c,
		13  // available from http://www.netlib.org/cephes/cmath.tgz.
		14  // The go code is a simplified version of the original C.
		15  //
		16  //			sin.c
		17  //
		18  //			Circular sine
		19  //
		20  // SYNOPSIS:
		21  //
		22  // double x, y, sin();
		23  // y = sin( x );
		24  //
		25  // DESCRIPTION:
		26  //
		27  // Range reduction is into intervals of pi/4.	The reduction error is nearly
		28  // eliminated by contriving an extended precision modular arithmetic.
		29  //
		30  // Two polynomial approximating functions are employed.
		31  // Between 0 and pi/4 the sine is approximated by
		32  //			x	+	x**3 P(x**2).
		33  // Between pi/4 and pi/2 the cosine is represented as
		34  //			1	-	x**2 Q(x**2).
		35  //
		36  // ACCURACY:
		37  //
		38  //											Relative error:
		39  // arithmetic	 domain			# trials			peak				 rms
		40  //		DEC			 0, 10			 150000			 3.0e-17		 7.8e-18
		41  //		IEEE -1.07e9,+1.07e9	130000			 2.1e-16		 5.4e-17
		42  //
		43  // Partial loss of accuracy begins to occur at x = 2**30 = 1.074e9.	The loss
		44  // is not gradual, but jumps suddenly to about 1 part in 10e7.	Results may
		45  // be meaningless for x > 2**49 = 5.6e14.
		46  //
		47  //			cos.c
		48  //
		49  //			Circular cosine
		50  //
		51  // SYNOPSIS:
		52  //
		53  // double x, y, cos();
		54  // y = cos( x );
		55  //
		56  // DESCRIPTION:
		57  //
		58  // Range reduction is into intervals of pi/4.	The reduction error is nearly
		59  // eliminated by contriving an extended precision modular arithmetic.
		60  //
		61  // Two polynomial approximating functions are employed.
		62  // Between 0 and pi/4 the cosine is approximated by
		63  //			1	-	x**2 Q(x**2).
		64  // Between pi/4 and pi/2 the sine is represented as
		65  //			x	+	x**3 P(x**2).
		66  //
		67  // ACCURACY:
		68  //
		69  //											Relative error:
		70  // arithmetic	 domain			# trials			peak				 rms
		71  //		IEEE -1.07e9,+1.07e9	130000			 2.1e-16		 5.4e-17
		72  //		DEC				0,+1.07e9	 17000			 3.0e-17		 7.2e-18
		73  //
		74  // Cephes Math Library Release 2.8:	June, 2000
		75  // Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
		76  //
		77  // The readme file at http://netlib.sandia.gov/cephes/ says:
		78  //		Some software in this archive may be from the book _Methods and
		79  // Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
		80  // International, 1989) or from the Cephes Mathematical Library, a
		81  // commercial product. In either event, it is copyrighted by the author.
		82  // What you see here may be used freely but it comes with no support or
		83  // guarantee.
		84  //
		85  //	 The two known misprints in the book are repaired here in the
		86  // source listings for the gamma function and the incomplete beta
		87  // integral.
		88  //
		89  //	 Stephen L. Moshier
		90  //	 [email protected]
		91  
		92  // sin coefficients
		93  var _sin = [...]float64{
		94  	1.58962301576546568060e-10, // 0x3de5d8fd1fd19ccd
		95  	-2.50507477628578072866e-8, // 0xbe5ae5e5a9291f5d
		96  	2.75573136213857245213e-6,	// 0x3ec71de3567d48a1
		97  	-1.98412698295895385996e-4, // 0xbf2a01a019bfdf03
		98  	8.33333333332211858878e-3,	// 0x3f8111111110f7d0
		99  	-1.66666666666666307295e-1, // 0xbfc5555555555548
	 100  }
	 101  
	 102  // cos coefficients
	 103  var _cos = [...]float64{
	 104  	-1.13585365213876817300e-11, // 0xbda8fa49a0861a9b
	 105  	2.08757008419747316778e-9,	 // 0x3e21ee9d7b4e3f05
	 106  	-2.75573141792967388112e-7,	// 0xbe927e4f7eac4bc6
	 107  	2.48015872888517045348e-5,	 // 0x3efa01a019c844f5
	 108  	-1.38888888888730564116e-3,	// 0xbf56c16c16c14f91
	 109  	4.16666666666665929218e-2,	 // 0x3fa555555555554b
	 110  }
	 111  
	 112  // Cos returns the cosine of the radian argument x.
	 113  //
	 114  // Special cases are:
	 115  //	Cos(±Inf) = NaN
	 116  //	Cos(NaN) = NaN
	 117  func Cos(x float64) float64 {
	 118  	if haveArchCos {
	 119  		return archCos(x)
	 120  	}
	 121  	return cos(x)
	 122  }
	 123  
	 124  func cos(x float64) float64 {
	 125  	const (
	 126  		PI4A = 7.85398125648498535156e-1	// 0x3fe921fb40000000, Pi/4 split into three parts
	 127  		PI4B = 3.77489470793079817668e-8	// 0x3e64442d00000000,
	 128  		PI4C = 2.69515142907905952645e-15 // 0x3ce8469898cc5170,
	 129  	)
	 130  	// special cases
	 131  	switch {
	 132  	case IsNaN(x) || IsInf(x, 0):
	 133  		return NaN()
	 134  	}
	 135  
	 136  	// make argument positive
	 137  	sign := false
	 138  	x = Abs(x)
	 139  
	 140  	var j uint64
	 141  	var y, z float64
	 142  	if x >= reduceThreshold {
	 143  		j, z = trigReduce(x)
	 144  	} else {
	 145  		j = uint64(x * (4 / Pi)) // integer part of x/(Pi/4), as integer for tests on the phase angle
	 146  		y = float64(j)					 // integer part of x/(Pi/4), as float
	 147  
	 148  		// map zeros to origin
	 149  		if j&1 == 1 {
	 150  			j++
	 151  			y++
	 152  		}
	 153  		j &= 7															 // octant modulo 2Pi radians (360 degrees)
	 154  		z = ((x - y*PI4A) - y*PI4B) - y*PI4C // Extended precision modular arithmetic
	 155  	}
	 156  
	 157  	if j > 3 {
	 158  		j -= 4
	 159  		sign = !sign
	 160  	}
	 161  	if j > 1 {
	 162  		sign = !sign
	 163  	}
	 164  
	 165  	zz := z * z
	 166  	if j == 1 || j == 2 {
	 167  		y = z + z*zz*((((((_sin[0]*zz)+_sin[1])*zz+_sin[2])*zz+_sin[3])*zz+_sin[4])*zz+_sin[5])
	 168  	} else {
	 169  		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])
	 170  	}
	 171  	if sign {
	 172  		y = -y
	 173  	}
	 174  	return y
	 175  }
	 176  
	 177  // Sin returns the sine of the radian argument x.
	 178  //
	 179  // Special cases are:
	 180  //	Sin(±0) = ±0
	 181  //	Sin(±Inf) = NaN
	 182  //	Sin(NaN) = NaN
	 183  func Sin(x float64) float64 {
	 184  	if haveArchSin {
	 185  		return archSin(x)
	 186  	}
	 187  	return sin(x)
	 188  }
	 189  
	 190  func sin(x float64) float64 {
	 191  	const (
	 192  		PI4A = 7.85398125648498535156e-1	// 0x3fe921fb40000000, Pi/4 split into three parts
	 193  		PI4B = 3.77489470793079817668e-8	// 0x3e64442d00000000,
	 194  		PI4C = 2.69515142907905952645e-15 // 0x3ce8469898cc5170,
	 195  	)
	 196  	// special cases
	 197  	switch {
	 198  	case x == 0 || IsNaN(x):
	 199  		return x // return ±0 || NaN()
	 200  	case IsInf(x, 0):
	 201  		return NaN()
	 202  	}
	 203  
	 204  	// make argument positive but save the sign
	 205  	sign := false
	 206  	if x < 0 {
	 207  		x = -x
	 208  		sign = true
	 209  	}
	 210  
	 211  	var j uint64
	 212  	var y, z float64
	 213  	if x >= reduceThreshold {
	 214  		j, z = trigReduce(x)
	 215  	} else {
	 216  		j = uint64(x * (4 / Pi)) // integer part of x/(Pi/4), as integer for tests on the phase angle
	 217  		y = float64(j)					 // integer part of x/(Pi/4), as float
	 218  
	 219  		// map zeros to origin
	 220  		if j&1 == 1 {
	 221  			j++
	 222  			y++
	 223  		}
	 224  		j &= 7															 // octant modulo 2Pi radians (360 degrees)
	 225  		z = ((x - y*PI4A) - y*PI4B) - y*PI4C // Extended precision modular arithmetic
	 226  	}
	 227  	// reflect in x axis
	 228  	if j > 3 {
	 229  		sign = !sign
	 230  		j -= 4
	 231  	}
	 232  	zz := z * z
	 233  	if j == 1 || j == 2 {
	 234  		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])
	 235  	} else {
	 236  		y = z + z*zz*((((((_sin[0]*zz)+_sin[1])*zz+_sin[2])*zz+_sin[3])*zz+_sin[4])*zz+_sin[5])
	 237  	}
	 238  	if sign {
	 239  		y = -y
	 240  	}
	 241  	return y
	 242  }
	 243  

View as plain text