How to check for NAN / INF / IND in C++

By , last updated May 9, 2017

Recently we had occasional, but serious problems with some software we’re making. The problems were with invalid floating point numbers or C++ NAN and IND/INF errors.

Read also: Theory behind C++ 1.#INF, -1.#INF, 1.#IND, -1.#IND, 1.#SNAN and #QNAN floating point numbers and errors

Once invalid (#IND / #INF / #NAN) numbers have infested your simulation, it’s very difficult to get rid of it. It’s like a viral infection. The best way to avoid invalid floating point numbers are to prevent them happening in the first place.

What happened was that invalid floating point values were introduced while calculating the angle between two vectors. The acos method calculate the angle, and it’s domain is [-1, 1]. Due to rounding errors, the actual value passed to acos was slightly less or slightly above the domain, which resulted in an invalid number.

The way we caught the error was to modify the vector3d-class and insert breakpoints when the expression value != value is true. Only NAN and IND values behave like that.

After the breakpoints were set, the call stack gave it all away.

Here is a sample program for detecting invalid numbers.


#include <iostream>     // cout
#include <math.h>       // acos
#include <float.h>      // DBL_MAX
#include <limits>       // numeric_limits

template<typename T>
bool is_infinite( const T &value )
{
    // Since we're a template, it's wise to use std::numeric_limits<T>
    //
    // Note: std::numeric_limits<T>::min() behaves like DBL_MIN, and is the smallest absolute value possible.
    //

    T max_value = std::numeric_limits<T>::max();
    T min_value = - max_value;

    return ! ( min_value <= value && value <= max_value );
}

template<typename T>
bool is_nan( const T &value )
{
    // True if NAN
    return value != value;
}

template<typename T>
bool is_valid( const T &value )
{
    return ! is_infinite(value) && ! is_nan(value);
}

int main()
{
    using std::cout;

    double a, b, c, d, e;

    a = 1.0;
    b = 0.0;
    c = a / c;          // divide by zero
    d = acos(-1.001);   // domain for acos is [-1, 1], anything else is #IND or inf
    e = b / b;          // zero / zero

    cout << "Value of a: " << a << " " << is_valid(a) << " " << (is_nan(a) ? " nan " : "") << (is_infinite(a) ? " infinite " : "") << "n";
    cout << "Value of b: " << b << " " << is_valid(b) << " " << (is_nan(b) ? " nan " : "") << (is_infinite(b) ? " infinite " : "") << "n";
    cout << "Value of c: " << c << " " << is_valid(c) << " " << (is_nan(c) ? " nan " : "") << (is_infinite(c) ? " infinite " : "") << "n";
    cout << "Value of d: " << d << " " << is_valid(d) << " " << (is_nan(d) ? " nan " : "") << (is_infinite(d) ? " infinite " : "") << "n";
    cout << "Value of e: " << e << " " << is_valid(e) << " " << (is_nan(e) ? " nan " : "") << (is_infinite(e) ? " infinite " : "") << "n";

    return 0;
}

Output is:

Value of a: 1 1
Value of b: 0 1
Value of c: inf 0  infinite
Value of d: nan 0  nan  infinite
Value of e: -nan 0  nan  infinite

Professional Software Developer, doing mostly C++. Connect with Kent on Twitter.

Comments

Be the first to comment.

Leave a Reply


You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*