NaNs Just Don't Get No Respect

F i L witte2008 at gmail.com
Sat Aug 18 02:31:58 PDT 2012


On Saturday, 18 August 2012 at 04:44:16 UTC, Jesse Phillips wrote:
> On Saturday, 18 August 2012 at 01:07:43 UTC, F i L wrote:
>> Your example:
>>
>>    float f;
>>    if (condition1)
>>        f = 7;
>>    ... code ...
>>    if (condition2)
>>        ++f;
>>
>> is flawed in that condition1 is _required_ to pass in sync 
>> with condition2, or you'll get a NaN in the result.
>
> It is not flawed as that is exactly what he said condition1 did 
> until the maintenance programmer made a change which caused 
> this to no longer be in sync with condition2 (most likely 
> fixing a bug as condition1 really should have been false).

It's flawed because condition2 relies upon condition1 to function 
without error. The example, as Walter presented it, is logically 
describing:

     float f;
     if (condition1) {
         f = 7;
         if (condition2)
             f ++;
     }

because the only way Walter's next argument, that "a programmer 
will haphazardly supply a default value where there _should_ be a 
NaN", is in error, because if condition2 _does_ rely upon 
condition1, then there _shouldn't_ be a NaN by the time 
condition2 is reached, as condition2 _should_ be nested (like 
above), and the programmer made a logical mistake (which the 
compiler can warn him about). Remember, NaN in this example is 
only used as error checking to ensure 'f' is assigned before it's 
manipulated.

If however, condition2 isn't intended to rely upon condition1, 
then 'f' needs to be explicitly assigned a usable value before 
condition2, and outside of condition1. Which also negates 
Walter's "haphazardly assigned" argument, because 'f' _isn't_ 
intended to be NaN (so assigning to 0.0f makes sense), and 
condition1 is the only place 'f' is assigned in the example.

The only way code like Walter's example is written, is when the 
coder has made a logical mistake. Which, again, the compiler can 
warn us about:

     float f;
     if (condition1)
         f = 7;
     // f _could_ be unassigned, therefor...
     if (condition2)
         f ++; // ...should be error


Furthermore, in a situation where the value _is_ intended to be 
NaN (for example, to check 'f' for NaN after condition2) then an 
explicit assignment to NaN will help document that intent, and 
help keep a third party from mistakenly assigning it to something 
else at a later date:

     float f = float.nan;
     if (condition1)
         f = 7;
     if (condition2)
         f ++;

     ...lotsa code...

     if (f == float.nan)
         doSomething();
     else
         doSomethingElse();

In this situation, if floats default to NaN and 'f' wasn't 
explicitly defined, a maintenance programmer might not recognize 
the last condition, think "gee, I need to set that to a value in 
case condition1 fails when condition2 does not", and mistakenly 
assign 'f' a usable value, thus introducing a silent bug.


More information about the Digitalmars-d-announce mailing list