Thread: isnan() and isinf() in C++

  1. #1
    Technical Lead QuantumPete's Avatar
    Join Date
    Aug 2007
    Location
    London, UK
    Posts
    894

    isnan() and isinf() in C++

    Hey everyone,
    I'm converting some C code that does horrible things to doubles. At some point I have a check that does
    Code:
    if (isnan(dblval) || isinf(dblval) { /* blah */}
    Now looking at limits.h I see the std::numeric_limits functions. My question is now. Is it legal to do:
    Code:
    if (std::numeric_limits<double>::infinity() == dblvalue) { /* blah */}
    since it compares two doubles directly, and what would be the a similar check for NaN?

    QuantumPete
    "No-one else has reported this problem, you're either crazy or a liar" - Dogbert Technical Support
    "Have you tried turning it off and on again?" - The IT Crowd

  2. #2
    Registered User OnionKnight's Avatar
    Join Date
    Jan 2005
    Posts
    555
    You cannot compare NAN like you can with infinity. Anything compared with NAN is false, so NAN == NAN is false. Use isnan() in the form of std::isnan(). If you really don't like it you can use dblvalue != dblvalue, but I find this far less readable.

  3. #3
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    Be aware that your current infinity test doesn't work like the usual 'isinf' or one conforming to the C99 standard. (It doesn't test for negative infinity.)

    Use isnan() in the form of std::isnan().
    Presumably he is trying to find a C++ root that will work with compilers that don't provide the extension/support C99.

    Soma

  4. #4
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    What's the difference between NaN and INF anyways?
    All my math teachers kept saying that x/0 isn't really infinity, it was Not a Number...
    "I am probably the laziest programmer on the planet, a fact with which anyone who has ever seen my code will agree." - esbo, 11/15/2008

    "the internet is a scary place to be thats why i dont use it much." - billet, 03/17/2010

  5. #5
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    What's the difference between NaN and INF anyways?
    Besides that one signals 'Not a Number' and the other signals infinity?! O_o

    All my math teachers kept saying that x/0 isn't really infinity, it was Not a Number...
    Well... for computers, whether or not dividing a number by zero results in positive infinity, negative infinity, or 'Not a Number' depends on the platform/settings/numerator involved. (Compile and test the output of "1.0/0.0", "-1.0/0.0", and "0.0/0.0" on your favorite platform.)

    It's just easier to debug source if you have complete information about the problem.

    Edit: And just for fun: with every floating-point implementation I know of, 'NaN' and infinity carry regardless of the mathematics operations involved; it is far faster to just perform the calculation than to check it before each successive operation.

    Soma
    Last edited by phantomotap; 09-10-2008 at 01:43 PM.

  6. #6
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by OnionKnight View Post
    You cannot compare NAN like you can with infinity. Anything compared with NAN is false, so NAN == NAN is false. Use isnan() in the form of std::isnan(). If you really don't like it you can use dblvalue != dblvalue, but I find this far less readable.
    I'm with you: I'd stick with the explicit isnan() test.

    Apart from the readability aspect, when testinging dblvalue != dblvalue, there is a small danger that an aggressive compiler will optimise out the test, and therefore never execute the intended code. I encountered one multi-platform Fortran compiler some years back that, when run with high optimisation settings, would do exactly that.

    Then again, I don't believe such tests are a good idea anyway: it is much easier to prove/ensure correct functioning of a program by designing it to ensure that NaN's cannot occur, rather than trying to detect them after the fact.

    IEEE Infinities are sometimes useful, as they have well-defined mathematical properties.
    Quote Originally Posted by cpjust View Post
    What's the difference between NaN and INF anyways?
    All my math teachers kept saying that x/0 isn't really infinity, it was Not a Number...
    Your math teachers are wrong.

    A number is formally defined as "an abstract object, tokens of which are used to count or measure". Infinity is formally a real number, albeit usually described as a limiting value (eg the limit as x->0 of 1/x). Dividing by zero is mathematically one of the processes that yields infinities.

    NaN in IEEE floating point indicates a value that is not real. For example, the result of computing square root of -1. INF is the result from certain operations (eg dividing a non-zero value by zero, the result of adding other INF values).
    Last edited by grumpy; 09-10-2008 at 03:19 PM.

  7. #7
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    I'd stick with the explicit isnan() test.
    As phantomotap already mentioned, isnan() is C99. It's quite possible that the OP's C++ compiler doesn't support it, or that the OP wants to avoid using it in case other compilers do not support it.

    (For what it's worth, my g++ 4.1.2 does have isnan().)
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  8. #8
    Registered User
    Join Date
    Oct 2001
    Posts
    2,129
    Quote Originally Posted by grumpy View Post
    Apart from the readability aspect, when testinging dblvalue != dblvalue, there is a small danger that an aggressive compiler will optimise out the test, and therefore never execute the intended code. I encountered one multi-platform Fortran compiler some years back that, when run with high optimisation settings, would do exactly that.
    How about this:
    Code:
    bool myisnan(double var)
    {
        volatile double temp = var;
        return temp != temp;
    }
    Last edited by robwhit; 09-10-2008 at 03:39 PM.

  9. #9
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by dwks View Post
    As phantomotap already mentioned, isnan() is C99. It's quite possible that the OP's C++ compiler doesn't support it, or that the OP wants to avoid using it in case other compilers do not support it.
    I'm not arguing with that; I simply noted, if you have to check for a NaN, better to be explicit about it rather then relying on an inequality test. I still maintain it is better to avoid NaN's (or, more accurately, the operations that produce them) in the first place.

    There's also the incidental fact - very inconvenient for those who rely on IEEE NaNs, INFs, etc - that not all compilers or systems support IEEE floating point formats.

  10. #10
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Quote Originally Posted by grumpy View Post
    Apart from the readability aspect, when testinging dblvalue != dblvalue, there is a small danger that an aggressive compiler will optimise out the test, and therefore never execute the intended code. I encountered one multi-platform Fortran compiler some years back that, when run with high optimisation settings, would do exactly that.
    GCC will do that if you compile with -ffast-math (or more specifically, -ffinite-math-only). The option tells the compiler to assume that there won't be any infinities or NaNs, so x != x cannot possibly yield anything but false.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  11. #11
    Technical Lead QuantumPete's Avatar
    Join Date
    Aug 2007
    Location
    London, UK
    Posts
    894
    Thanks for all your help guys. In the end, I decided to just stick with isnan() and isinf, it seems that while our cmath library doesn't have an std::isnan() it has a C implementation.

    QuantumPete
    "No-one else has reported this problem, you're either crazy or a liar" - Dogbert Technical Support
    "Have you tried turning it off and on again?" - The IT Crowd

  12. #12
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by robwhit View Post
    How about this:
    Code:
    bool myisnan(double var)
    {
        volatile double temp = var;
        return temp != temp;
    }
    Having to declare a variable as volatile in order to test if it is a Nan is somewhat excessive.

    And it wouldn't necessarily prevent an aggressive compiler always returning false anyway.

  13. #13
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by grumpy View Post
    Having to declare a variable as volatile in order to test if it is a Nan is somewhat excessive.

    And it wouldn't necessarily prevent an aggressive compiler always returning false anyway.
    An aggressive compiler that is optimizing access to volatile would be BAD. It should not do that - that's the ENTIRE PURPOSE of volatile.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  14. #14
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by matsp View Post
    An aggressive compiler that is optimizing access to volatile would be BAD. It should not do that - that's the ENTIRE PURPOSE of volatile.
    Except that, volatile or not, the comparison "b != b" only needs to fetch the value of b once because there are no sequence points in it. And testing if a value is not equal to itself is a trivial logical operation, which an optimiser can gleefully evaluate without accessing the value at all. In fact, the optimiser would need to have special logic introduced to it for handling of expressions involving IEEE floating point values: for other types, the optimisation is perfectly acceptable. Use of volatile does not change that.

    If you want to use volatile to trick an aggressive compiler, it is necessary to add sequence points and ensure multiple variable accesses occur.
    Code:
    bool myisnan(double var)
    {
        volatile double temp1 = var;
        volatile double temp2 = var;
        return temp1 != temp2;
    }
    which actually forces the value of temp1 and temp2 (and therefore var) to be fetched twice. There are ways aggressive compilers could mangle this too (eg recognise that temp1 and temp2 are local to the function, so nothing else can modify them, which opens the door for optimising the variables out of existence).

    Optimisers are complex bits of code, and devious techniques are needed to prevent an overly aggressive optimiser from doing its thing.

    Which comes back to the original point: if you want to test for NaN or infinities, use a library function that is known to work with your compiler.

  15. #15
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by grumpy View Post
    Optimisers are complex bits of code, and devious techniques are needed to prevent an overly aggressive optimiser from doing its thing.
    Maybe it would be good to add a #pragma to the C/C++ standard to do something like this:
    Code:
    #pragma no_optimize_begin
    bool myisnan(double var)
    {
        volatile double temp = var;
        return temp != temp;
    }
    #pragma no_optimize_end
    "I am probably the laziest programmer on the planet, a fact with which anyone who has ever seen my code will agree." - esbo, 11/15/2008

    "the internet is a scary place to be thats why i dont use it much." - billet, 03/17/2010

Popular pages Recent additions subscribe to a feed