Hi All,
I'm writing an application that does a lot of work with angles and times. Calculation precision is better than one milli-arcsecond in angle and one millisecond in time. I carry angles as radians and times as either Julian dates (days) or Julian centuries. It's all done with
double
s.
As you can imagine, one millisecond expressed as a Julian century is a pretty small number:
0.001 / (86400 * 36525)
roughly equals 3e-13
So I use a pair of doubles to represent the "large" and "small" portions of a date to maintain full precision when calculating small differences.
In many parts of the code it is possible to generate an invalid angle or time. To handle this the classes have
invalidate()
and
isValid()
functions to set and get their validity.
The classes used to carry a Boolean member variable to indicate validity, but some time ago I dropped it in favour of setting the doubles themselves to a value that represents "invalid". I've been using
1e37
as this value (I chose it because it's close to
FLT_MAX
), and this simple comparison has always worked (presumably because I'm comparing a constant with itself):
1 2 3 4 5 6 7
|
// do something that invalidates the object
double result = INVALID; // INVALID == 1e37
...
// elsewhere, test for validity
bool isValid = (result != INVALID);
|
Every part of the code (hopefully) invalidates a double by directly assigning it the value INVALID.
However, I wonder if it is only a matter of time before this type of comparison fails, and lately I've been tinkering with using an Epsilon comparison to make the check more robust. I've obtained some code that uses an absolute Epsilon comparison if the numbers are genuinely close and a relative Epsilon comparison if they aren't. (There are many other places where I check for equality between two doubles, so I need this more robust code anyway.)
But it seems to me that comparing 1e37 with 3e-13 is probably asking for trouble when the relative Epsilon value becomes something like 2e21 (based on
DBL_EPSILON * 1.0e37
). That said, no other valid value could reach 1e21, so perhaps the check is safe after all?
My questions are:
Is there a better number than 1e37 to represent an invalid double? Is it safe to use a quiet NaN and test for validity using
isnan()
?
Or, should I go back to carrying a Boolean validity flag as a member variable? (I don't remember why I dropped it, but I think it was something to do with eliminating what I thought at the time were unnecessary member variables. It was a while ago.)
Cheers,
Frank