8 ms·
This was confusing: > and divide by zero is explicitly named as undefined behavior in 5.6.4 I thought, how can this possibly be true if IEEE-754 specifically
by conistonwater 11y ago
This was confusing:
> and divide by zero is explicitly named as undefined behavior in 5.6.4
I thought, how can this possibly be true if IEEE-754 specifically defines 1.0/-0.0 == -inf.
So I looked it up, and the actual rule seems to be
> If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined.
So divide-by-zero is only undefined behaviour if the result is not representable. But it is representable in IEEE-754 (adherence to which is implementation-defined), so it should be fine.
That said, I still don't understand how it's not a constant expression. Perhaps it's because in IEEE-754 it can sometimes cause a divide-by-zero exception, depending on flag settings? Because to check something is negative zero it's enough to do something like
x == 0 && 1/x == -inf
- twoodfin 11y agoSo divide-by-zero is only undefined behaviour if the result is not representable. But it is representable in IEEE-754 (adherence to which is implementation-defined), so it should be fine. That's not how I read the line of the standard you quoted. ISTM it's saying: (Result not mathematically defined) ∨ (Result not in the range of representable values) ⇒ Behavior is undefined In this case, 1.0/-0.0 is mathematically undefined as C++ specifies such things (I believe division-by-zero is called out specifically as such), and it doesn't help that IEEE-754 can represent it anyway. It's still a useful representation in the language because you can reach it through a series of calculations that are all included in the range of defined behavior. I'm also skeptical that x == 0 && 1/x == -inf will work reliably for just that reason: I believe a compiler would be perfectly within its rights to unconditionally treat this expression as false, since x == 0 would imply UB. Not at all an expert here, so would enjoy having a standards lawyer set me straight.
- conistonwater 11y agoPerhaps you're right. I just find IEEE-754's approach clear, and C++'s rule confusing. I would say that 1.0/-0.0 is mathematically defined in the pure sense: IEEE-754 defines a specific model of real numbers closed under such operations [-inf,inf]\union{NaN}. The thing is that that test should definitely work under IEEE-754, so I would be very surprised if C++ somehow forbids you from getting the IEEE-standard behaviour. For reference, here's a proof that it's correct: $ stack repl λ> import Data.SBV λ> prove $ do x <- sFloat "x"; return $ fpIsNegativeZero x <=> (x .== 0 &&& 1/x .== -infinity) Q.E.D.
- mikeash 11y agoUndefined behavior means anything can happen, and "anything" includes "following IEEE-754 rules." Any given C++ implementation is free to implement this case to follow IEEE-754 and declare that this behavior is supported.
- deleted 11y ago[deleted]
- conistonwater 11y agoI see, that makes sense given how the C++ standard omits specifying floating-point arithmetic. But isn't there still a problem, given that in the article clang gave the error message error: '(1.0e+0f / -0.0f)' is not a constant expression and the proposed explanation is that "undefined behavior is unusable in a constant expression"? So it seems clang is not following IEEE-754 rules. As I read 5.20.2.5 in N4296, undefined behaviour may not occur in constant expressions, so clang is not free to follow IEEE-754 for the division-by-zero, even though it can do that in regular code, because then it's UB. And anyway, why isn't it UB to invoke UB in a constant expression?
- mikeash 11y agoI think you're right, the compiler can follow IEEE-754 rules in general, but as written it couldn't do so for constant expressions. I find that rule to be really weird in general. Does that mean that, for example, if you try to use "1 << 32" in a constant expression, then whether it's actually a constant expression will depend on the target architecture? I wonder what the rationale is there.
- twoodfin 11y agoI find that rule to be really weird in general. Does that mean that, for example, if you try to use "1 << 32" in a constant expression, then whether it's actually a constant expression will depend on the target architecture? I wonder what the rationale is there. Yes, that's right. The rationale is that it's not particularly different from the way constant expressions in C have always worked: The compiler knows full well whether static const int x = 99999999999; or static const int x = 1 << 32; represents a valid assignment within the range of int on the target platform, and responds accordingly. constexpr just generalizes that behavior to more of the expression machinery.
- jadamcze 11y ago5.6.4 in N4296 has this text: "If the second operand of / or % is zero the behavior is undefined."