3

Consider the following code:

#include <iostream>

int main()
{
    double zero = 0;
    const double ZERO = 0.;
    std::cout << 0/zero << "\n"; // -nan
    std::cout << 0/0. << "\n";   // nan
    std::cout << 0/ZERO << "\n"; // nan
}

Why does 0/zero produces -nan, why it differs from 0/0. and what is the meaning of -nan?

Live demo here for clang. GCC gives -nan for all these cases. Trying to compile with MSVC leads to complile error for const values and -nan for variable.

Which compiler is the more correct by Standard in this case?

αλεχολυτ
  • 4,792
  • 1
  • 35
  • 71
  • 4
    Division by zero is undefined. Anything and everything is both correct and not correct. – molbdnilo Aug 01 '17 at 20:29
  • `nan` is `Not a Number`, it's used in floating point when there's no valid result possible. – Barmar Aug 01 '17 at 20:32
  • Note if you had tried with constant expressions [it would have been ill-formed and required a diagnostic](https://stackoverflow.com/a/29237475/1708801) – Shafik Yaghmour Aug 01 '17 at 20:49
  • @ShafikYaghmour: Is floating-point division by zero considered undefined even on implementations where `std::numeric_limits::is_iec559` reports IEC-compatible math, and would thus required to implement floating-point corner-case behaviors [including floating-point division by zero] in a manner consistent with that Standard? [the linked page used *integer* division]. – supercat Aug 01 '17 at 21:01
  • @supercat if it is undefined behavior then it is [ill-formed in a constant expression](https://stackoverflow.com/q/21319413/1708801) and requires a diagnostic. [T.C.'s comments help clarify this a bit](https://stackoverflow.com/questions/34276373/self-initialization-of-a-static-constexpr-variable-is-it-well-formed#comment56295043_34276373). – Shafik Yaghmour Aug 01 '17 at 21:06
  • @ShafikYaghmour: Floating-point division by zero would *generally* be Undefined Behavior, but if an implementation's `std::numeric_limits::is_iec559` reports IEC-compatible math, that would guarantee behavior in some cases where the Standard would *otherwise* impose no requirements. If an implementation supports IEC-compatible math, the behavior of evaluating x/0.0 is defined as yielding one of three values based upon the value of x. – supercat Aug 01 '17 at 21:38
  • @supercat well, ubsan still trigger even if that is the case [see it live](https://wandbox.org/permlink/P0Ac4afyc70OenNa) ... so I don't think that is a correct interpretation ... maybe it is worth a bug report to clarify? – Shafik Yaghmour Aug 21 '17 at 21:16
  • @ShafikYaghmour: A quality sanitizer should allow such behaviors to be configured. The purpose of such programs is to detect constructs which may work on some machines, but not on *all machines of interest*. If one will want to run code on some machines that support IEC559 and some that don't, one will want a sanitizer to squawk at things that would be UB on the machines that don't support IEC559, even if it's running on a machine that does. – supercat Aug 22 '17 at 00:08

1 Answers1

2

From the C++ Standard 5.6.4:

If the second operand of / or % is zero the behavior is undefined.

Division by 0 causes the dreaded undefined behaviour! So the compiler is free to do anything included generating a NaN, writing code that crashes, and raiding your fridge. There isn't a more correct behaviour.

For floating-point types, C++ has std::numeric_limits<T>::is_iec559 to test whether or not the implementation supports the IEEE 754 standard for dealing with floating-points of type T.

Paul Evans
  • 27,315
  • 3
  • 37
  • 54
  • 3
    If an implementation promises to use Annex-F-complaint math (common, though by no means universal), floating-point division by zero has behavior defined by that spec, and would thus not invoke UB. – supercat Aug 01 '17 at 20:44
  • @supercat Yes, but the OP asks about what is "more correct by [the] Standard". An implementation could also promise to raid your fridge :P – Paul Evans Aug 01 '17 at 20:48
  • @PaulEvans: At least in C, if an implementation defines `__STDC_IEC_559__`, floating-point division by zero would not invoke UB on that implementation, since IEC559 defines the behavior and the C Standard would incorporate that by reference. The C++ Standard incorporates much of the C Standard by reference, but I'm not familiar enough with the ins and outs to know if it excludes Annex F guarantees. – supercat Aug 01 '17 at 20:55
  • 1
    @supercat C++ has [std::numeric_limits::is_iec559](http://en.cppreference.com/w/cpp/types/numeric_limits/is_iec559) to test whether or not the implementation supports IEC 559 for type `T`. – Paul Evans Aug 01 '17 at 21:01
  • 1
    Division by 0 in floats is implementation defined. – SergeyA Aug 01 '17 at 21:06
  • 1
    @SergeyA Please see the C++ standard 5.6.4 – Paul Evans Aug 01 '17 at 21:18
  • @supercat -- regardless of what an implementation promises, the behavior of a program that divides by zero is undefined. That **only** means that the **standard** doesn't tell you what the program should do. Implementations are free to do whatever they like when a program has undefined behavior, including doing something perfectly sensible. They are not required to do nasty things. – Pete Becker Aug 01 '17 at 21:23
  • @PaulEvans there is also 5.4, which somewhat legitimizes this (*and usually adjustable by library functions*). – SergeyA Aug 01 '17 at 21:34
  • @SergeyA section 5.4 in C++14 is [expr.cast] which has nothing to do with this topic – M.M Aug 01 '17 at 22:00
  • @M.M, http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf is where I am looking at, and it is not section [expr.cast], I used wrong numbering, should be 5/4. Begins with 'If during the evaluation of an expression...' – SergeyA Aug 01 '17 at 22:04
  • @SergeyA do you know why implementation choose `-nan` for this case instead of ordinary `nan`? – αλεχολυτ Aug 02 '17 at 10:13
  • @alexolut, no, I do not see a reason for this. According to IEEE 754, this should produce NaN, since both operands are not negative. – SergeyA Aug 02 '17 at 13:11
  • @SergeyA you can find an answer on [ruSO](https://ru.stackoverflow.com/a/701038/176217). – αλεχολυτ Aug 02 '17 at 13:15
  • @alexolut, yeah, found it independently. I am not sure the behavior is conforming, though. – SergeyA Aug 02 '17 at 13:16
  • @PeteBecker: In the C Stanard N1570, *An arithmetic constant expression of floating type, other than one in an initializer for an object that has static or thread storage duration, is evaluated (as if) during execution; thus, it is affected by any operative floating-point control modes and raises floating-point exceptions as required by IEC 60559 (provided the state for the FENV_ACCESS pragma is ''on'').*. C++ has additional cases where it evaluates things at compile time, like the right-hand side of `const` declarations, but certainly in C the behavior of the run-time `0.0/0.0` is defined... – supercat Aug 02 '17 at 22:07
  • ...by the Standard for implementations that support Annex F [above text is from F.8.4, btw]. – supercat Aug 02 '17 at 22:07