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(NaN, 0) returns an incorrect value #66338

Closed
jackvonhouse opened this issue Mar 15, 2024 · 5 comments
Closed

math: Pow(NaN, 0) returns an incorrect value #66338

jackvonhouse opened this issue Mar 15, 2024 · 5 comments

Comments

@jackvonhouse
Copy link

Go version

go version go1.22.1 linux/amd64

Output of go env in your module/workspace:

GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/home/user/.cache/go-build'
GOENV='/home/user/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/user/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/user/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/lib/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/lib/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.22.1'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/dev/null'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build4272126422=/tmp/go-build -gno-record-gcc-switches'

What did you do?

I'm trying to take:

  • 0 to a power of NaN;
  • NaN to a power of 0.

https://go.dev/play/p/OdD0TalqBrN

What did you see happen?

I see output:

NaN
1

What did you expect to see?

The comments to the Pow function give examples of return values:

go/src/math/pow.go

Lines 31 to 32 in db6097f

// Pow(NaN, y) = NaN
// Pow(x, NaN) = NaN

The result should be as in the comments or it should return 1 1 as it does in the IEEE Std. 754-2008 "Section 9.2.1 Special values". Either way it seems to me that these two edge cases should return the same value.

It's probably due to a case order problem:

go/src/math/pow.go

Lines 55 to 62 in db6097f

func pow(x, y float64) float64 {
switch {
case y == 0 || x == 1:
return 1
case y == 1:
return x
case IsNaN(x) || IsNaN(y):
return NaN()

This example should handle the case on line 61. But due to a higher-priority case on line 57 an incorrect value is returned.

I think it would be more correct to move a case with NaN checks to the begin or move all edge cases at the beginning of the pow function from switch-case to if statement like this:

func pow(x, y float64) float64 {
	if IsNaN(x) || IsNaN(y) {
		return NaN()
	}

	if y == 1 {
		return x
	}
	
	// Other edge cases ...
	
	// Calculate pow ...
}
@seankhliao
Copy link
Member

feel free to submit a CL/PR

@seankhliao seankhliao added the NeedsFix The path to resolution is known, but the work has not been done. label Mar 15, 2024
@randall77
Copy link
Contributor

This behavior is correct given the special cases listed in the docs for Pow. The zero exponent is the first, and highest priority, special case.

@seankhliao seankhliao removed the NeedsFix The path to resolution is known, but the work has not been done. label Mar 15, 2024
@jackvonhouse
Copy link
Author

@randall77

This behavior is correct given the special cases listed in the docs for Pow. The zero exponent is the first, and highest priority, special case.

How behavior can be correct if there is one result in the function's comments and docs and another result in fact? Either the comments and documentation are lying or this case is being handled incorrectly. Please write why this is correct behavior, given that doc and the IEEE 754-2008 standard state the opposite.

@randall77
Copy link
Contributor

Read the doc comment carefully.

Special cases are (in order):
//	Pow(x, ±0) = 1 for any x
...
//	Pow(NaN, y) = NaN

Note the "in order", and the fact that the first one matches the input described.

I don't know whether we diverge from IEEE 754 or not, but even if we did this is certainly a weird enough case that it doesn't warrant making a backwards-incompatible change to the spec and behavior.

@randall77
Copy link
Contributor

From IEEE 754 2008:

For the pow function (integral exponents get special treatment):
pow(x, ±0) is 1 for any x (even a zero, quiet NaN, or infinity)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants