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

compiler: conversion from Infinity to integer is always negative #56023

Closed
robpike opened this issue Oct 4, 2022 · 6 comments
Closed

compiler: conversion from Infinity to integer is always negative #56023

robpike opened this issue Oct 4, 2022 · 6 comments

Comments

@robpike
Copy link
Contributor

robpike commented Oct 4, 2022

Consider the conversion

int64(math.Inf(+1))

I would expect a largest positive integer, but in fact the result is the largest negative integer. I have a feeling the conversion is broken. Perhaps that's what the hardware does, but it's not what the spec claims happens. This negative result happens for all signed integer types, except int8, which yields 0. See

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

which is

package main

import (
	"fmt"
	"math"
)

func main() {
	fmt.Println(int(math.Inf(+1)))
	fmt.Println(int(math.Inf(-1)))
	fmt.Println(int(math.Inf(+1)) == int(math.Inf(-1)))

	fmt.Println(int8(math.Inf(+1)))
	fmt.Println(int8(math.Inf(-1)))
	fmt.Println(int8(math.Inf(+1)) == int8(math.Inf(-1)))

	fmt.Println(int16(math.Inf(+1)))
	fmt.Println(int16(math.Inf(-1)))
	fmt.Println(int16(math.Inf(+1)) == int16(math.Inf(-1)))

	fmt.Println(int32(math.Inf(+1)))
	fmt.Println(int32(math.Inf(-1)))
	fmt.Println(int32(math.Inf(+1)) == int32(math.Inf(-1)))

	fmt.Println(int64(math.Inf(+1)))
	fmt.Println(int64(math.Inf(-1)))
	fmt.Println(int64(math.Inf(+1)) == int64(math.Inf(-1)))
}

This was reported on the mailing list: https://groups.google.com/g/golang-nuts/c/pRUoXRt7syk/m/_jnc1N48DQAJ?utm_medium=email&utm_source=footer&pli=1

I note that in limited testing, C seems to honor the sign.

@cuonglm
Copy link
Member

cuonglm commented Oct 4, 2022

This negative result happens for all signed integer types, except int8, which yields 0.

Seem happens with int16, too.

On arm64:

== int ==
9223372036854775807
-9223372036854775808
false
== int8 ==
-1
0
false
== int16 ==
-1
0
false
== int32 ==
2147483647
-2147483648
false
== int64 ==
9223372036854775807
-9223372036854775808
false

@robpike
Copy link
Contributor Author

robpike commented Oct 4, 2022

@cuonglm Thanks, that confirms this is a compiler bug.
@randall77

@ianlancetaylor
Copy link
Member

With gccgo the original program prints

9223372036854775807
-9223372036854775808
false
127
-128
false
32767
-32768
false
2147483647
-2147483648
false
9223372036854775807
-9223372036854775808
false

@randall77
Copy link
Contributor

From the spec:

In all non-constant conversions involving floating-point or complex values, if the result type cannot represent the value the conversion succeeds but the result value is implementation-dependent.

Which I believe covers this case.

We use the instruction CVTTSD2SQ (aka CVTTSD2SI in intel parlance).

From the intel docs, it does:

If a converted result is larger than the maximum signed doubleword integer, the floating point invalid exception is raised. If this exception is masked, the indefinite integer value (80000000H) is returned.

(I believe that doc is for 32-bit, for 64-bit there are more zeroes.)
That would lead to a result of -1<<63.

@robpike
Copy link
Contributor Author

robpike commented Oct 4, 2022

Not that it's a critical case, but it's bothersome how much variation there is between architectures. But "implementation-defined" allows that.

At least there were no NaNs involved.

@randall77
Copy link
Contributor

I don't see anything to fix here, so closing.
If we wanted floating point stuff like this to be well-defined, or just architecture-independent, we could maybe do that. But that's a proposal, not a bug fix.

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

5 participants