http://studiofreya.com/c/how-to-check-for-nan-inf-ind-in-c/
Recently we had occasional, but serious problems with some software we’re making. The problems were with invalid floating point numbers.
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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
#include
#include
#include
#include
template
<
typename
T>
bool
is_infinite(
const
T &value )
{
// Since we're a template, it's wise to use std::numeric_limits
//
// Note: std::numeric_limits
//
T max_value = std::numeric_limits
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:
1
2
3
4
5
|
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
|