Skip to content

math: Remainder(-1,1) returns 0 instead of -0 (as IEEE 754 requires) #30814

@dr2chase

Description

@dr2chase

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

Go version is tip.

Does this issue reproduce with the latest release?

yes

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

go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/drchase/Library/Caches/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/drchase/work/gocode"
GOPROXY=""
GORACE=""
GOROOT="/Users/drchase/work/go"
GOTMPDIR=""
GOTOOLDIR="/Users/drchase/work/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/dev/null"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/gr/vvb66dqx6jl6lh8wckfd5p9w0095tn/T/go-build197631297=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

math.Remainder(-1,1)
https://play.golang.org/p/EZjSc56D0ax

What did you expect to see?

-0

What did you see instead?

0

Documentation for math.Remainder claims IEEE 754:

Remainder returns the IEEE 754 floating-point remainder of x/y.

IEEE 754-1985 (the copy of the standard I could easily find) Section 5.1, second paragraph:

When y != 0 , the remainder r = x REM y is defined regardless of the
rounding mode by the mathematical relation r = x – y × n , where n is the
integer nearest the exact value x/y ; whenever |n – x/y| = ½ , then n is even.
Thus, the remainder is always exact. If r = 0 , its sign shall be that of x.
Precision control (4.3) shall not apply to the remainder operation.

The cause of the bug is these lines in math/remainder.go:

	if x == y {
		return 0
	}

Changing them to read:

	if x == y {
		if !sign {
			return 0
		}
		return -(x-x) // How to say "-0.0" in Go.
	}

fixes the bug, at least on amd64.

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsFixThe path to resolution is known, but the work has not been done.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions