I got a calculation result from GNU Scientific Library. It looks like this
iter 0: A = 1.0000, lambda = 1.0000, b = 0.0000, cond(J) = inf, |f(x)| = 101.0200
iter 1: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) = 92.8216, |f(x)| = -nan
iter 2: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) = nan, |f(x)| = -nan
iter 3: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) = nan, |f(x)| = -nan
iter 4: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) = nan, |f(x)| = -nan
iter 5: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) = nan, |f(x)| = -nan
iter 6: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) = nan, |f(x)| = -nan
iter 7: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) = nan, |f(x)| = -nan
iter 8: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) = nan, |f(x)| = -nan
iter 9: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) = nan, |f(x)| = -nan
iter 10: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) = nan, |f(x)| = -nan
iter 11: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) = nan, |f(x)| = -nan
iter 12: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) = nan, |f(x)| = -nan
iter 13: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) = nan, |f(x)| = -nan
iter 14: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) = nan, |f(x)| = -nan
iter 15: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) = nan, |f(x)| = -nan
iter 16: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) = nan, |f(x)| = -nan
iter 17: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) = nan, |f(x)| = -nan
iter 18: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) = nan, |f(x)| = -nan
iter 19: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) = nan, |f(x)| = -nan
iter 20: A = 3.5110, lambda = -12.8820, b = 1.2364, cond(J) = nan, |f(x)| = -nan
So, you see cond(J) = nan, |f(x)| = -nan
from 2nd iteration. From the language design perspective, what is the purpose of having "nan" silently, rather than abort? Efficiency?
From the language design perspective, what is the purpose of having "nan" silently, rather than abort? Efficiency?
Efficiency is one reason. But another is that C lacks the concept of exceptions. Consider the following. You're using a pre-compiled library where you have no access to the source. You only have the header and the object file, so you have a function double f(double arg)
that is declared in the header and defined in the object file.
So what if you don't want the program to crash? Then you would have to make sure that the function is not even called if arg
is a value such that f
would return NaN
. This can be very tricky indeed. Especially in this case where you don't even have access to the source.
In Java, an exception is not thrown when NaN is calculated. But if it were, you would do something like this:
try {
a = f(4.0);
} catch (NaNException) {
How would you do that in C? This is actually a problem in C when it comes to division by zero with integers. That invokes undefined behavior in C, with no chance to recover.
This java code:
try {
a = 100/d;
} catch (ArithmeticExpression) {
System.out.println("<d> must not be zero");
corresponds to this C code:
if(d == 0) {
puts("<d> must not be zero");
} else {
a = 100/d;
Note that you must do the check before, which can be MUCH trickier than doing it afterwards. In this simple case it's trivial. But consider a slightly less trivial example. Imagine that you have a function that performs a total of 20 divisions. Then you might need 20 if-statements to cover this. And we also have the case mentioned above, where you don't have access to the source and just have to rely on pure faith in those who created the library.
NaN means the involved calculation is meaningless or totally erroneous, right?
Not really. The code could be completely ok, and the error could be that the code has been given wrong input. That does not necessarily mean that the program needs to crash.
And the error handling in C is basically that it is always up to the programmer to do proper error checking.
Actually, you could use NAN
as an explicit error indicator. Example:
double f(double arg) {
if(arg < 0)
return NAN;
...
}
But be careful, because this will not work:
if(f(a) == NAN) {
Instead, use this:
if(isnan(f(a))) {