Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

math: tan function returns different results depending on platform #18354

Closed
deafgoat opened this issue Dec 16, 2016 · 7 comments
Closed

math: tan function returns different results depending on platform #18354

deafgoat opened this issue Dec 16, 2016 · 7 comments

Comments

@deafgoat
Copy link
Contributor

Please answer these questions before submitting your issue. Thanks!

What version of Go are you using (go version)?

OS X: go version go1.6 darwin/amd64
PowerPC (PPC): go version go1.4.2 gccgo (GCC) 5.4.0 linux/ppc64le
s390x: go version go1.4.2 gccgo (GCC) 5.4.0 linux/s390x

What operating system and processor architecture are you using (go env)?

OS X:

GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/gopath"
GORACE=""
GOROOT="/usr/local/opt/go/libexec"
GOTOOLDIR="/usr/local/opt/go/libexec/pkg/tool/darwin_amd64"
GO15VENDOREXPERIMENT="1"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fno-common"
CXX="clang++"
CGO_ENABLED="1"

PPC:

GOARCH="ppc64le"
GOBIN=""
GOCHAR="9"
GOEXE=""
GOHOSTARCH="ppc64le"
GOHOSTOS="linux"
GOOS="linux"
GOPATH=""
GORACE=""
GOROOT="/opt/toolchain"
GOTOOLDIR="/opt/toolchain/libexec/gcc/ppc64le-linux/5.4.0"
CC="/opt/toolchain/bin/gcc"
GOGCCFLAGS="-fPIC -pthread -fmessage-length=0"
CXX="/opt/toolchain/bin/g++"
CGO_ENABLED="1"

s390x:

GOARCH="s390x"
GOBIN=""
GOCHAR=""
GOEXE=""
GOHOSTARCH="s390x"
GOHOSTOS="linux"
GOOS="linux"
GOPATH=""
GORACE=""
GOROOT="/opt/toolchain/"
GOTOOLDIR="/opt/toolchain/libexec/gcc/s390x-linux/5.4.0"
CC="/opt/toolchain/bin/gcc"
GOGCCFLAGS="-fPIC -pthread -fmessage-length=0"
CXX="/opt/toolchain/bin/g++"
CGO_ENABLED="1"

What did you do?

Ran this program:

package main

import (
	"fmt"
	"math"
)

func main() {
	fmt.Printf("sin(20): %v\n", math.Sin(20))
	fmt.Printf("cos(20): %v\n", math.Cos(20))
	fmt.Printf("tan(20): %v\n", math.Tan(20))
	fmt.Printf("sin(20)/cos(20): %v\n", math.Sin(20)/math.Cos(20))
}

Play at https://play.golang.org/p/vfEPHNlzIo

What did you expect to see?

sin(20): 0.9129452507276277
cos(20): 0.40808206181339196
tan(20): 2.2371609442247427
sin(20)/cos(20): 2.2371609442247427

What did you see instead?

On OS X, worked as expected but on PPC and s390x, saw this instead:

sin(20): 0.9129452507276277
cos(20): 0.40808206181339196
tan(20): 2.237160944224742
sin(20)/cos(20): 2.2371609442247427

Note the difference in the result of tan(20).

Browsing through the source, it appears to be a difference between the pure-Go implementation and various assembly implementations for the tan function.

I believe PPC & s390 use the pure-Go implementation while my OS X box uses assembly (as does any arm, amd64, 386 box).

Here's the diff for the 0 <= n <= 100:

$ diff osx ppc
2c2
< 1 1.557407724654902
---
> 1 1.5574077246549023
6c6
< 5 -3.3805150062465854
---
> 5 -3.380515006246586
9c9
< 8 -6.799711455220378
---
> 8 -6.799711455220379
11,13c11,13
< 10 0.6483608274590867
< 11 -225.95084645419516
< 12 -0.6358599286615807
---
> 10 0.6483608274590866
> 11 -225.95084645419513
> 12 -0.6358599286615808
15,16c15,16
< 14 7.244606616094805
< 15 -0.8559934009085188
---
> 14 7.2446066160948055
> 15 -0.8559934009085187
21,22c21,22
< 20 2.2371609442247427
< 21 -1.5274985276366033
---
> 20 2.237160944224742
> 21 -1.5274985276366035
24c24
< 23 1.588153083391274
---
> 23 1.5881530833912738
27,28c27,28
< 26 1.17875355420628
< 27 -3.2737038004281196
---
> 26 1.1787535542062797
> 27 -3.273703800428119
36,37c36,37
< 35 0.47381472041445105
< 36 7.750470905699147
---
> 35 0.473814720414451
> 36 7.750470905699148
39,43c39,43
< 38 0.31030966099480106
< 39 3.6145544071015347
< 40 -1.1172149309238961
< 41 0.16065669868064286
< 42 2.291387992437486
---
> 38 0.310309660994801
> 39 3.614554407101535
> 40 -1.117214930923896
> 41 0.16065669868064283
> 42 2.2913879924374863
51c51
< 50 -0.2719006119976307
---
> 50 -0.27190061199763077
59c59
< 58 8.33085685249046
---
> 58 8.330856852490458
62c62
< 61 3.743167944272419
---
> 61 3.7431679442724195
67,69c67,69
< 66 0.026560517776039395
< 67 1.6523172640102348
< 68 -2.040081598015946
---
> 66 0.02656051777603939
> 67 1.6523172640102353
> 68 -2.0400815980159464
71,72c71,72
< 70 1.2219599181369432
< 71 -3.0776204031933605
---
> 70 1.2219599181369434
> 71 -3.07762040319336
77c77
< 76 0.6867476893515229
---
> 76 0.6867476893515227
84c84
< 83 3.880596310384247
---
> 83 3.880596310384246
88c88
< 87 -1.4424174716642322
---
> 87 -1.4424174716642324
90c90
< 89 1.685825370506016
---
> 89 1.6858253705060158
93c93
< 92 1.244270058128709
---
> 92 1.2442700581287092
95,98c95,98
< 94 -0.2529780967613676
< 95 0.9357524720632394
< 96 -5.451340110823242
< 97 -0.4103212990482421
---
> 94 -0.2529780967613677
> 95 0.9357524720632393
> 96 -5.451340110823241
> 97 -0.41032129904824216
101c101
< 100 -0.587213915156929
---
> 100 -0.5872139151569291
103,104c103,104

Is this expected/accepted behavior?

@bradfitz bradfitz added this to the Go1.9 milestone Dec 16, 2016
@bradfitz
Copy link
Contributor

@ianlancetaylor
Copy link
Contributor

Personally I don't think we should promise that all floating point math operations will return exactly the same result on all platforms. See #17895.

However, you are asking a slightly different question: should we promise that the math functions will return the same result for the same arguments on all platforms? If we want to make that promise, we will have to give up the assembly implementations of most math functions. So again I'm inclined to say that we should not make that promise. People who need identical results on all platforms must take other approaches--for example, copy the pure Go implementation from the math package.

I note that in C, running on amd64, I get the results that you get on PPC.

@bradfitz
Copy link
Contributor

That's what I guessed the answer would be, so we don't give up performance for most users. In any case, we should document it probably, at least in the package doc.

@minux
Copy link
Member

minux commented Dec 18, 2016 via email

@gulyasm
Copy link
Contributor

gulyasm commented Jan 7, 2017

I added a note to the top level math documentation that the result might not be the same on different architectures. As a guidance, is it ok to state it only there, or should I add this to the individual methods?

@ianlancetaylor
Copy link
Contributor

Personally I think the package documentation is sufficient.

The language itself does not guarantee that the results of floating point operations will be the same on all architectures. See #17895 .

@gopherbot
Copy link

CL https://golang.org/cl/34938 mentions this issue.

gopherbot pushed a commit that referenced this issue Jun 6, 2017
Updates #18354.

Change-Id: I76bc4a73d8dc99eeda14b395e451d75a65184191
Reviewed-on: https://go-review.googlesource.com/45013
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
@golang golang locked and limited conversation to collaborators Jun 6, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants