Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
go
Commits
739c442e
Commit
739c442e
authored
Oct 31, 2011
by
Charles L. Dorian
Committed by
Russ Cox
Oct 31, 2011
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
math: Improved accuracy for Sin and Cos.
Fixes #1564. R=rsc, dchest CC=golang-dev
https://golang.org/cl/5320056
parent
48c75c5f
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
201 additions
and
43 deletions
+201
-43
src/pkg/math/all_test.go
src/pkg/math/all_test.go
+3
-3
src/pkg/math/sin.go
src/pkg/math/sin.go
+198
-40
No files found.
src/pkg/math/all_test.go
View file @
739c442e
...
...
@@ -1709,7 +1709,7 @@ func TestCopysign(t *testing.T) {
func
TestCos
(
t
*
testing
.
T
)
{
for
i
:=
0
;
i
<
len
(
vf
);
i
++
{
if
f
:=
Cos
(
vf
[
i
]);
!
close
(
cos
[
i
],
f
)
{
if
f
:=
Cos
(
vf
[
i
]);
!
very
close
(
cos
[
i
],
f
)
{
t
.
Errorf
(
"Cos(%g) = %g, want %g"
,
vf
[
i
],
f
,
cos
[
i
])
}
}
...
...
@@ -2192,7 +2192,7 @@ func TestSignbit(t *testing.T) {
}
func
TestSin
(
t
*
testing
.
T
)
{
for
i
:=
0
;
i
<
len
(
vf
);
i
++
{
if
f
:=
Sin
(
vf
[
i
]);
!
close
(
sin
[
i
],
f
)
{
if
f
:=
Sin
(
vf
[
i
]);
!
very
close
(
sin
[
i
],
f
)
{
t
.
Errorf
(
"Sin(%g) = %g, want %g"
,
vf
[
i
],
f
,
sin
[
i
])
}
}
...
...
@@ -2205,7 +2205,7 @@ func TestSin(t *testing.T) {
func
TestSincos
(
t
*
testing
.
T
)
{
for
i
:=
0
;
i
<
len
(
vf
);
i
++
{
if
s
,
c
:=
Sincos
(
vf
[
i
]);
!
close
(
sin
[
i
],
s
)
||
!
close
(
cos
[
i
],
c
)
{
if
s
,
c
:=
Sincos
(
vf
[
i
]);
!
veryclose
(
sin
[
i
],
s
)
||
!
very
close
(
cos
[
i
],
c
)
{
t
.
Errorf
(
"Sincos(%g) = %g, %g want %g, %g"
,
vf
[
i
],
s
,
c
,
sin
[
i
],
cos
[
i
])
}
}
...
...
src/pkg/math/sin.go
View file @
739c442e
// Copyright 20
09
The Go Authors. All rights reserved.
// Copyright 20
11
The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
...
...
@@ -6,60 +6,218 @@ package math
/*
Floating-point sine and cosine.
Coefficients are #5077 from Hart & Cheney. (18.80D)
*/
func
sinus
(
x
float64
,
quad
int
)
float64
{
// The original C code, the long comment, and the constants
// below were from http://netlib.sandia.gov/cephes/cmath/sin.c,
// available from http://www.netlib.org/cephes/cmath.tgz.
// The go code is a simplified version of the original C.
//
// sin.c
//
// Circular sine
//
// SYNOPSIS:
//
// double x, y, sin();
// y = sin( x );
//
// DESCRIPTION:
//
// Range reduction is into intervals of pi/4. The reduction error is nearly
// eliminated by contriving an extended precision modular arithmetic.
//
// Two polynomial approximating functions are employed.
// Between 0 and pi/4 the sine is approximated by
// x + x**3 P(x**2).
// Between pi/4 and pi/2 the cosine is represented as
// 1 - x**2 Q(x**2).
//
// ACCURACY:
//
// Relative error:
// arithmetic domain # trials peak rms
// DEC 0, 10 150000 3.0e-17 7.8e-18
// IEEE -1.07e9,+1.07e9 130000 2.1e-16 5.4e-17
//
// Partial loss of accuracy begins to occur at x = 2**30 = 1.074e9. The loss
// is not gradual, but jumps suddenly to about 1 part in 10e7. Results may
// be meaningless for x > 2**49 = 5.6e14.
//
// cos.c
//
// Circular cosine
//
// SYNOPSIS:
//
// double x, y, cos();
// y = cos( x );
//
// DESCRIPTION:
//
// Range reduction is into intervals of pi/4. The reduction error is nearly
// eliminated by contriving an extended precision modular arithmetic.
//
// Two polynomial approximating functions are employed.
// Between 0 and pi/4 the cosine is approximated by
// 1 - x**2 Q(x**2).
// Between pi/4 and pi/2 the sine is represented as
// x + x**3 P(x**2).
//
// ACCURACY:
//
// Relative error:
// arithmetic domain # trials peak rms
// IEEE -1.07e9,+1.07e9 130000 2.1e-16 5.4e-17
// DEC 0,+1.07e9 17000 3.0e-17 7.2e-18
//
// Cephes Math Library Release 2.8: June, 2000
// Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
//
// The readme file at http://netlib.sandia.gov/cephes/ says:
// Some software in this archive may be from the book _Methods and
// Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
// International, 1989) or from the Cephes Mathematical Library, a
// commercial product. In either event, it is copyrighted by the author.
// What you see here may be used freely but it comes with no support or
// guarantee.
//
// The two known misprints in the book are repaired here in the
// source listings for the gamma function and the incomplete beta
// integral.
//
// Stephen L. Moshier
// moshier@na-net.ornl.gov
// sin coefficients
var
_sin
=
[
...
]
float64
{
1.58962301576546568060E-10
,
// 0x3de5d8fd1fd19ccd
-
2.50507477628578072866E-8
,
// 0xbe5ae5e5a9291f5d
2.75573136213857245213E-6
,
// 0x3ec71de3567d48a1
-
1.98412698295895385996E-4
,
// 0xbf2a01a019bfdf03
8.33333333332211858878E-3
,
// 0x3f8111111110f7d0
-
1.66666666666666307295E-1
,
// 0xbfc5555555555548
}
// cos coefficients
var
_cos
=
[
...
]
float64
{
-
1.13585365213876817300E-11
,
// 0xbda8fa49a0861a9b
2.08757008419747316778E-9
,
// 0x3e21ee9d7b4e3f05
-
2.75573141792967388112E-7
,
// 0xbe927e4f7eac4bc6
2.48015872888517045348E-5
,
// 0x3efa01a019c844f5
-
1.38888888888730564116E-3
,
// 0xbf56c16c16c14f91
4.16666666666665929218E-2
,
// 0x3fa555555555554b
}
// Cos returns the cosine of x.
//
// Special conditions are:
// Cos(±Inf) = NaN
// Cos(NaN) = NaN
func
Cos
(
x
float64
)
float64
{
const
(
P0
=
.1357884097877375669092680e8
P1
=
-
.4942908100902844161158627e7
P2
=
.4401030535375266501944918e6
P3
=
-
.1384727249982452873054457e5
P4
=
.1459688406665768722226959e3
Q0
=
.8644558652922534429915149e7
Q1
=
.4081792252343299749395779e6
Q2
=
.9463096101538208180571257e4
Q3
=
.1326534908786136358911494e3
PI4A
=
7.85398125648498535156E-1
// 0x3fe921fb40000000, Pi/4 split into three parts
PI4B
=
3.77489470793079817668E-8
// 0x3e64442d00000000,
PI4C
=
2.69515142907905952645E-15
// 0x3ce8469898cc5170,
M4PI
=
1.273239544735162542821171882678754627704620361328125
// 4/pi
)
// TODO(rsc): Remove manual inlining of IsNaN, IsInf
// when compiler does it for us
// special cases
switch
{
case
x
!=
x
||
x
<
-
MaxFloat64
||
x
>
MaxFloat64
:
// IsNaN(x) || IsInf(x, 0):
return
NaN
()
}
// make argument positive
sign
:=
false
if
x
<
0
{
x
=
-
x
quad
=
quad
+
2
}
x
=
x
*
(
2
/
Pi
)
/* underflow? */
var
y
float64
if
x
>
32764
{
var
e
float64
e
,
y
=
Modf
(
x
)
e
=
e
+
float64
(
quad
)
f
,
_
:=
Modf
(
0.25
*
e
)
quad
=
int
(
e
-
4
*
f
)
}
else
{
k
:=
int32
(
x
)
y
=
x
-
float64
(
k
)
quad
=
(
quad
+
int
(
k
))
&
3
j
:=
int64
(
x
*
M4PI
)
// integer part of x/(Pi/4), as integer for tests on the phase angle
y
:=
float64
(
j
)
// integer part of x/(Pi/4), as float
// map zeros to origin
if
j
&
1
==
1
{
j
+=
1
y
+=
1
}
j
&=
7
// octant modulo 2Pi radians (360 degrees)
if
j
>
3
{
j
-=
4
sign
=
!
sign
}
if
j
>
1
{
sign
=
!
sign
}
if
quad
&
1
!=
0
{
y
=
1
-
y
z
:=
((
x
-
y
*
PI4A
)
-
y
*
PI4B
)
-
y
*
PI4C
// Extended precision modular arithmetic
zz
:=
z
*
z
if
j
==
1
||
j
==
2
{
y
=
z
+
z
*
zz
*
((((((
_sin
[
0
]
*
zz
)
+
_sin
[
1
])
*
zz
+
_sin
[
2
])
*
zz
+
_sin
[
3
])
*
zz
+
_sin
[
4
])
*
zz
+
_sin
[
5
])
}
else
{
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
])
}
if
quad
>
1
{
if
sign
{
y
=
-
y
}
yy
:=
y
*
y
temp1
:=
((((
P4
*
yy
+
P3
)
*
yy
+
P2
)
*
yy
+
P1
)
*
yy
+
P0
)
*
y
temp2
:=
((((
yy
+
Q3
)
*
yy
+
Q2
)
*
yy
+
Q1
)
*
yy
+
Q0
)
return
temp1
/
temp2
return
y
}
// Cos returns the cosine of x.
func
Cos
(
x
float64
)
float64
{
// Sin returns the sine of x.
//
// Special conditions are:
// Sin(±0) = ±0
// Sin(±Inf) = NaN
// Sin(NaN) = NaN
func
Sin
(
x
float64
)
float64
{
const
(
PI4A
=
7.85398125648498535156E-1
// 0x3fe921fb40000000, Pi/4 split into three parts
PI4B
=
3.77489470793079817668E-8
// 0x3e64442d00000000,
PI4C
=
2.69515142907905952645E-15
// 0x3ce8469898cc5170,
M4PI
=
1.273239544735162542821171882678754627704620361328125
// 4/pi
)
// TODO(rsc): Remove manual inlining of IsNaN, IsInf
// when compiler does it for us
// special cases
switch
{
case
x
==
0
||
x
!=
x
:
// x == 0 || IsNaN():
return
x
// return ±0 || NaN()
case
x
<
-
MaxFloat64
||
x
>
MaxFloat64
:
// IsInf(x, 0):
return
NaN
()
}
// make argument positive but save the sign
sign
:=
false
if
x
<
0
{
x
=
-
x
sign
=
true
}
return
sinus
(
x
,
1
)
}
// Sin returns the sine of x.
func
Sin
(
x
float64
)
float64
{
return
sinus
(
x
,
0
)
}
j
:=
int64
(
x
*
M4PI
)
// integer part of x/(Pi/4), as integer for tests on the phase angle
y
:=
float64
(
j
)
// integer part of x/(Pi/4), as float
// map zeros to origin
if
j
&
1
==
1
{
j
+=
1
y
+=
1
}
j
&=
7
// octant modulo 2Pi radians (360 degrees)
// reflect in x axis
if
j
>
3
{
sign
=
!
sign
j
-=
4
}
z
:=
((
x
-
y
*
PI4A
)
-
y
*
PI4B
)
-
y
*
PI4C
// Extended precision modular arithmetic
zz
:=
z
*
z
if
j
==
1
||
j
==
2
{
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
])
}
else
{
y
=
z
+
z
*
zz
*
((((((
_sin
[
0
]
*
zz
)
+
_sin
[
1
])
*
zz
+
_sin
[
2
])
*
zz
+
_sin
[
3
])
*
zz
+
_sin
[
4
])
*
zz
+
_sin
[
5
])
}
if
sign
{
y
=
-
y
}
return
y
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment