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

strconv.ParseFloat issue with darwin/arm64 #48145

Closed
nchanged opened this issue Sep 2, 2021 · 4 comments
Closed

strconv.ParseFloat issue with darwin/arm64 #48145

nchanged opened this issue Sep 2, 2021 · 4 comments

Comments

@nchanged
Copy link

nchanged commented Sep 2, 2021

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

$ go version
go version go1.17 darwin/arm64

Does this issue reproduce with the latest release?

Yes

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

go env Output
$ go env
GO111MODULE=""
GOARCH="arm64"
GOBIN=""
GOCACHE="/Users/nc/Library/Caches/go-build"
GOENV="/Users/nc/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/nc/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/nc/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/opt/homebrew/Cellar/go/1.17/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/opt/homebrew/Cellar/go/1.17/libexec/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.17"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/nc/work/akkurate/DataService/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/pc/tqh7913x2dj0k92fqwm1hhy40000gn/T/go-build553045848=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

package main

import (
	
	"strconv"
)

func main() {
	initialValue, _ := strconv.ParseFloat("10000", 64)
	println(0.1*initialValue-float64(1000))
}

What did you expect to see?

It works on Linux
https://play.golang.org/p/7qcKKj-RFd9

0

What did you see instead?

That's what I see on my MacBook

+5.551115e-014
@randall77
Copy link
Contributor

I believe this is FMA happening on arm64. See the floating-point operators section of https://golang.org/ref/spec#Arithmetic_operators .
The problem is 0.1 is not exactly 1/10 in floating point, so 0.1 * 10000 - 1000 is not zero, if you compute it without intermediately rounding 0.1 * 10000.

@nchanged
Copy link
Author

nchanged commented Sep 2, 2021

@randall77 I don't think that resolves my issue:

initialValue, _ := strconv.ParseFloat("10000", 64)
println(0.1*initialValue - 1000)

staticValue := float64(10000)
println(initialValue == staticValue) // true

println(0.1*staticValue - 1000)

If you take a look a this code, you will see that both values are the same and give true when comparing. However, the result is different.

+5.551115e-014
true
+0.000000e+000

On Linux the results are consistent. Magic?
https://play.golang.org/p/stcNSR-825A

Either way, one would expect a consistent behavior on all platforms

@randall77
Copy link
Contributor

println(0.1*staticValue - 1000)

This is evaluated at compile time, so FMA is not used.

This program demonstrates the difference (without needing to invoke strconv to get a non-constant float):

package main

func main() {
	println(f(10000))
}

//go:noinline
func f(x float64) float64 {
	return 0.1*x - 1000
}

It will print 0 on amd64, but that small number you've seen on arm64.

Either way, one would expect a consistent behavior on all platforms

That is not the semantics of Go, unfortunately. Floating point results do vary by platform, and are allowed to by the spec.

@nchanged
Copy link
Author

nchanged commented Sep 2, 2021

Thanks!

prashantkhoje added a commit to prashantkhoje/geo that referenced this issue Jul 27, 2022
This was exposed while testing CockroachDB.
Following tests from pkg/sql/opt/exec/execbuilder fail due to floating point precision differences caused by FMA:
- TestExecBuild/local/geospatial
- TestExecBuild/local-vec-off/geospatial
- TestExecBuild/local-spec-planning/geospatial
- TestExecBuild/fakedist/geospatial
- TestExecBuild/fakedist-vec-off/geospatial
- TestExecBuild/fakedist-metadata/geospatial
- TestExecBuild/fakedist-disk/geospatial
- TestExecBuild/fakedist-spec-planning/geospatial

With explicit casts in this patch, these failures are resolved.

References:
https://go.dev/ref/spec#Floating_point_operators
golang/go#53297
golang/go#48145
disintegration/gift#20 (comment)
@golang golang locked and limited conversation to collaborators Sep 2, 2022
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

3 participants