
AMDG On 10/01/2012 03:43 AM, Andrew Sutton wrote:
Unless you mean to say that any program that uses a NaN in any way has undefined behavior, this notion of a "well-formed value" seems arbitrary and capricious.
The notion of "well-formed value" comes for Elements of Programming. NaN is given as an example of something that is not well-formed. It's defined in the first couple of pages, IIRC. Any state of an object that does represent a value (e.g., NaN does not represent a real number) is not a well-formed value. I can assure that neither Alex nor Paul would consider the definition to be arbitrary or capricious.
Well, I beg to differ.
A program that checks for NaN as the result of an invalid computation does not have undefined behavior because it is explicitly checking for that state. A program that uses NaN as if it were a real number should have undefined behavior.
That's no different from saying that a program that uses 2 + 3i as if it were a real number has undefined behavior. If you make an assumption about the value of an object, then it's likely to be undefined behavior if that assumption doesn't hold.
It is easy to construct examples of programs where NaN breaks the postconditions of STL algorithms:
double s[] { NaN }; assert(find(s, s + 1, NaN) == s); // will fail
double s[] { ..., NaN, ... }; sort(s, s + N); assert(is_sorted(s, s + N)); // probably fails
Comparisons on NaN do not conform to the usual semantics of equality and ordering, and so the programs have undefined behavior.
Some algorithms obviously won't work, but others like copy that don't depend on comparison will work fine. You can even use find or is_sorted if you pass a custom predicate that handles NaN's in a way consistent with what the algorithm expects. In short, the fact that NaN's cause undefined behavior is a property of the concept map of comparison for double, not a property of double in itself.
This is because the algorithms are generic and are only concerned with the comparison of values, not the checking of those computations for invalid results.
There's nothing wrong with having a type or set of types with a representation that includes an ill-formed value. It can be very useful for checking error states. However, such states may not be included in the set of values represented by that type.
As far as I'm concerned, any value that can exist at all is a member of the set of values represented by the type. The fact that some values are forbidden in certain contexts is irrelevant. A NaN: - Can have various basic operations applied to it with well-defined results. - Can appear in program input and output. - Can be used safely in some generic algorithms. Therefore, I maintain that a NaN is a legitimate value. Saying that it is ill-formed depends solely on the intent of the programmer in specific cases and is not a universal truth. In Christ, Steven Watanabe