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

spec: floating-point division by zero shouldn't be implementation defined #43577

Open
ianlancetaylor opened this issue Jan 7, 2021 · 4 comments
Labels
NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@ianlancetaylor
Copy link
Contributor

The spec says `The result of a floating-point or complex division by zero is not specified beyond the IEEE-754 standard; whether a run-time panic occurs is implementation-specific. This dates back to https://golang.org/cl/1081041, which was a general change about division by zero.

I think this is incorrect. Division by zero is fully defined by IEEE-754. There should not be a run-time panic for floating-point division by zero. This should be fully defined, not implementation-defined.

CC @griesemer

@ianlancetaylor ianlancetaylor added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Jan 7, 2021
@ianlancetaylor ianlancetaylor added this to the Backlog milestone Jan 7, 2021
@griesemer
Copy link
Contributor

This doesn't say that it's undefined, it just says it's not defined beyond the IEEE-754 standard. Specifically (https://en.wikipedia.org/wiki/IEEE_754#Exception_handling):

The standard defines five exceptions, each of which returns a default value and has a corresponding status flag that is raised when the exception occurs.[e] No other exception handling is required, but additional non-default alternatives are recommended (see § Alternate exception handling).

While this section (later on) defines that division-by-zero results in an infinity, it also says: "additional non-default alternatives are recommended".

The additional alternatives (https://en.wikipedia.org/wiki/IEEE_754#Alternate_exception_handling) include traps, etc.

I think this is the original reason why we didn't pin this down more precisely. In the past, on some FPUs, whether a trap happens upon division-by-zero depended on the FPU flag register. Unless I am misremembering, some OS didn't use to save/restore that register upon context switches, making in impractical to rely on a specific flag setting but the one provided by the OS. Consequently, requiring a specific behavior (no traps upon division by zero) was basically impossible to guarantee (albeit in practice, no "reasonable" program would ever change that register).

These problems may not exist anymore (to be investigated).

@ianlancetaylor
Copy link
Contributor Author

We can guarantee that division by zero does not trap, because we can set the floating-point control word on program startup. Or on systems where that is impossible because the floating-point control word is not saved on context switches, we can compile a floating-point division to check for a zero divisor. But the floating-point control word is always saved on context switches, because anything else would break threaded C code.

In C, if FE_DIVBYZERO is defined in <fenv.h>, then the system can control whether it traps on division-by-zero or simply returns an infinity (or NaN for 0.0 / 0.0). I checked every glibc target. FE_DIVBYZERO is defined for all of them except nios2 and microblaze. For nios2 it is omitted because division by zero always produces infinity/NaN, and never traps. For Microblaze the flag is omitted because on Microblaze you can either enable all floating-point exceptions or none; you can't enable specific exceptions.

In practice I am not aware of any system that defaults to trapping on floating-point division by zero. All systems I know of simply produce a floating-point infinity.

@josharian
Copy link
Contributor

we can set the floating-point control word on program startup.

Can we guarantee it stays set? I am reminded of #8623

@ianlancetaylor
Copy link
Contributor Author

We can ensure it stays set by forcing it on cgo calls and callbacks if necessary. (But, again, all systems I know of do what we want anyhow.)

cben added a commit to cben/rosa that referenced this issue Sep 19, 2022
Zero cost is the norm for ROSA quotas, and int/int division by zero would
cause a Go panic.  Float division by 0 de-facto returns +Inf but formally
is implemetation defined (golang/go#43577).
So added a guard `if`.

I guess in practice this hasn't exploded because on query we ask backend
only for GPU quotas `quota_id~='gpu'`?
cben added a commit to cben/rosa that referenced this issue Sep 19, 2022
Zero cost is the norm for ROSA quotas, and int/int division by zero would
cause a Go panic.  Float division by 0 de-facto returns +Inf but formally
is implemetation defined (golang/go#43577).
So added a guard `if`.

I guess in practice this hasn't exploded because on query we ask backend
only for GPU quotas `quota_id~='gpu'`?
cben added a commit to cben/rosa that referenced this issue Feb 20, 2023
Zero cost is the norm for ROSA quotas, and int/int division by zero would
cause a Go panic.  Float division by 0 de-facto returns +Inf but formally
is implemetation defined (golang/go#43577).
So added a guard `if`.

I guess in practice this hasn't exploded because on query we ask backend
only for GPU quotas `quota_id~='gpu'`?
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

3 participants