1

I would like to get straight on terminology. Consider:

for (double d = 0.0; d != 1.0; d += 0.1)
    cout << d << " ";

If I understand correctly, since double arithmetic is imprecise, this loop can be either finite or infinite. Is this considered unspecified or undefined behavior?

AlwaysLearning
  • 7,257
  • 4
  • 33
  • 68
  • 2
    No, it's not unspecified or undefined behavior, it's simply how floating point numbers work. Due to the rounding errors, `d != 1.0` can be `true` even if `d` "should" be `1.0`, and also `d` will stop increasing at some point once it is so big that the +0.1 will be rounded down. – Blaze Oct 28 '19 at 09:50

1 Answers1

6

The behaviour of your program is implementation defined: Different implementations can have different behavior, but they must document it. This is different from unspecified behavior (need not be documented) and undefined behavior (anything goes). See also Undefined, unspecified and implementation-defined behavior.

A common implementation of double is defined by IEEE754. If that standard is followed by your implementation, then that loop will always recover the same output.

Your loop is infinite under IEEE754 - you'll skip over 1.0 and eventually d will grow to such a size where adding 0.1 is a no-op.

Max Langhof
  • 23,383
  • 5
  • 39
  • 72
Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • 1
    ...for the same binary, floating point environment settings, OS and hardware. If any of them change you might not get the same output. – Max Langhof Oct 28 '19 at 09:53
  • @MaxLanghof: No, I think that's all in the IEEE754 spec. Although an implementation might not implement it faithfully (e.g. non-strict FP). – Bathsheba Oct 28 '19 at 09:54
  • I'm not sure that's true, IEEE754 specifies several rounding modes at least: https://en.wikipedia.org/wiki/Floating-point_arithmetic#Rounding_modes. But yes, for simple arithmetic like this the OS and hardware might be irrelevant as long as the rounding mode is constant (and the compiler is compliant). – Max Langhof Oct 28 '19 at 09:58
  • Wikipedia says: "Unspecified behavior is behavior that may vary on different implementations of a programming language." How is *implementation defined* different from *unspecified behavior*? – AlwaysLearning Oct 28 '19 at 10:02
  • "Implementation defined" means the implementation has to explicitly define what it's going to do. Unspecified behaviour means the implementation doesn't have to specify (i.e. document) the behaviour. – Bathsheba Oct 28 '19 at 10:03
  • 2
    @AlwaysLearning See also [`[defns.impl.defined]`](http://eel.is/c++draft/defns.impl.defined), [`[defns.unspecified]`](http://eel.is/c++draft/defns.unspecified), and [`[defns.undefined]`](http://eel.is/c++draft/defns.undefined). – Max Langhof Oct 28 '19 at 10:04
  • @MaxLanghof: That's gotta be a candidate for "comment of the day". If only you could pass a bounty to a comment. – Bathsheba Oct 28 '19 at 10:05
  • @Bathsheba Thanks! (Even though I wouldn't consider it really noteworthy :D) Feel free to add it to your answer if you want! – Max Langhof Oct 28 '19 at 10:07
  • @MaxLanghof: I've wiki'd the answer so you can make the edits as you please. – Bathsheba Oct 28 '19 at 10:08
  • @Bathsheba: The Standard is deliberately vague as to the level of detail with which behaviors must be specified. If it would be expensive to make a behavior behave precisely consistently, and if such consistency would have little value for some kinds of applications, an implementation shouldn't be required to behave consistently. – supercat Oct 28 '19 at 16:07