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: Pow() results are less accurate than libc pow() #25270

Open
yuvalif opened this issue May 6, 2018 · 5 comments
Open

math: Pow() results are less accurate than libc pow() #25270

yuvalif opened this issue May 6, 2018 · 5 comments
Labels
NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@yuvalif
Copy link

yuvalif commented May 6, 2018

Please see detailed discussion on the topic here: https://groups.google.com/forum/#!topic/golang-nuts/LqVD5kMHJQw

Note that the headline is about Fibonacci numbers, however, the root issue is regarding the accuracy of math.Pow, compare to libc pow() function.

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

go version go1.9.5 linux/amd64

Does this issue reproduce with the latest release?

did not test with go1.10, but could not find anything related to math performance in release notes

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

$ go env
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/ylifshit/go"
GORACE=""
GOROOT="/usr/lib/golang"
GOTOOLDIR="/usr/lib/golang/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build223266492=/tmp/go-build -gno-record-gcc-switches"
CXX="g++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"

What did you do?

compare accuracy of math.Pow tolibc pow(). cod, as well as detailed results are in the go-nuts discussion above

What did you expect to see?

see group discussion above

What did you see instead?

see group discussion above

@ALTree
Copy link
Member

ALTree commented May 6, 2018

We don't guarantee last-bit precision on float64 functions; there are other math functions that are not as good as the ones in glibc. See #9546 and #9545.

@ALTree ALTree changed the title math.Pow() results are less accurate than libc pow() math: Pow() results are less accurate than libc pow() May 6, 2018
@yuvalif
Copy link
Author

yuvalif commented May 6, 2018

is this "by design"? or something that would be addressed in the future?

@ALTree
Copy link
Member

ALTree commented May 6, 2018

As rsc wrote in the old golang-dev thread about this:

In general, for me, the answer to whether there is a problem depends on how complex the solutions are. If there is an easy way to get the correctly-rounded answer, great. If not, then I think it's fine to keep using the off-by-1-ulp code until an easy way presents itself.

For these specific cases, if we're on par with fdlibm, I think that's a fine bar, and you're welcome to close the issues with a note to that effect.

@ianlancetaylor
Copy link
Contributor

Please add the details with specific examples in this issue, rather than making people sort through a lengthy mailing list thread. Thanks.

@ianlancetaylor ianlancetaylor added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label May 7, 2018
@ianlancetaylor ianlancetaylor added this to the Unplanned milestone May 7, 2018
@bmkessler
Copy link
Contributor

From the referenced thread, the example given is that:

x = 1.618033988749895
n = 33.0
    math.Pow(x, n) = 7.881196000000127e+06
math/big Pow(x, n) = 7.881196000000136e+06

where the math.Pow result is low compared to the correctly rounded result from arbitrary precision calculation using math/big, which the c++ stdlib produces.

The raw binary representations to see the error in the last places clearly:

    math.Pow(x, n) = 0100000101011110000100000111101100000000000000000000000010001000
math/big Pow(x, n) = 0100000101011110000100000111101100000000000000000000000010010010

In this calculation with integer exponent, the error is solely due to floating point error from repeated multiplications. The only way that I know to improve this is to use higher precision for the internal calculations, with associated performance and complexity impacts. Note that the correctly rounded result for this case can be obtained by using 64 bits of precision, i.e. 80 bit extended precision floats aka long double (these are available in x87 FPU). I'm not sure what internal precision the c++ stdlib is using, but pow is known for having more difficulty obtaining accurate results than other elementary functions.

Playground summarizing the calculation is here.
https://play.golang.org/p/6YWN815h-w4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

4 participants