Checking if a double (or float) is NaN in C++

后端 未结 21 2285
北恋
北恋 2020-11-22 05:10

Is there an isnan() function?

PS.: I\'m in MinGW (if that makes a difference).

I had this solved by using isnan() from , which doe

21条回答
  •  深忆病人
    2020-11-22 05:34

    nan prevention

    My answer to this question is don't use retroactive checks for nan. Use preventive checks for divisions of the form 0.0/0.0 instead.

    #include 
    float x=0.f ;             // I'm gonna divide by x!
    if( !x )                  // Wait! Let me check if x is 0
      x = FLT_MIN ;           // oh, since x was 0, i'll just make it really small instead.
    float y = 0.f / x ;       // whew, `nan` didn't appear.
    

    nan results from the operation 0.f/0.f, or 0.0/0.0. nan is a terrible nemesis to the stability of your code that must be detected and prevented very carefully1. The properties of nan that are different from normal numbers:

    • nan is toxic, (5*nan=nan)
    • nan is not equal to anything, not even itself (nan != nan)
    • nan not greater than anything (nan !> 0)
    • nan is not less than anything (nan !< 0)

    The last 2 properties listed are counter-logical and will result in odd behavior of code that relies on comparisons with a nan number (the 3rd last property is odd too but you're probably not ever going to see x != x ? in your code (unless you are checking for nan (unreliably))).

    In my own code, I noticed that nan values tend to produce difficult to find bugs. (Note how this is not the case for inf or -inf. (-inf < 0) returns TRUE, ( 0 < inf ) returns TRUE, and even (-inf < inf) returns TRUE. So, in my experience, the behavior of the code is often still as desired).

    what to do under nan

    What you want to happen under 0.0/0.0 must be handled as a special case, but what you do must depend on the numbers you expect to come out of the code.

    In the example above, the result of (0.f/FLT_MIN) will be 0, basically. You may want 0.0/0.0 to generate HUGE instead. So,

    float x=0.f, y=0.f, z;
    if( !x && !y )    // 0.f/0.f case
      z = FLT_MAX ;   // biggest float possible
    else
      z = y/x ;       // regular division.
    

    So in the above, if x were 0.f, inf would result (which has pretty good/nondestructive behavior as mentioned above actually).

    Remember, integer division by 0 causes a runtime exception. So you must always check for integer division by 0. Just because 0.0/0.0 quietly evaluates to nan doesn't mean you can be lazy and not check for 0.0/0.0 before it happens.

    1 Checks for nan via x != x are sometimes unreliable (x != x being stripped out by some optimizing compilers that break IEEE compliance, specifically when the -ffast-math switch is enabled).

提交回复
热议问题