I was implementing an algorithm to calculate natural logs in C.
double taylor_ln(int z) {
double sum = 0.0;
double tmp = 1.0;
int i = 1;
while(tmp != 0.0) {
tmp = (1.0 / i) * (pow(((z - 1.0) / (z + 1.0)), i));
printf("(1.0 / %d) * (pow(((%d - 1.0) / (%d + 1.0)), %d)) = %f\n", i, z, z, i, tmp);
sum += tmp;
i += 2;
}
return sum * 2;
}
As shown by the print statement, tmp does equal 0.0 eventually, however, the loop continues. What could be causing this?
I am on Fedora 14 amd64 and compiling with:
clang -lm -o taylor_ln taylor_ln.c
Example:
$ ./taylor_ln 2
(1.0 / 1) * (pow(((2 - 1.0) / (2 + 1.0)), 1)) = 0.333333
(1.0 / 3) * (pow(((2 - 1.0) / (2 + 1.0)), 3)) = 0.012346
(1.0 / 5) * (pow(((2 - 1.0) / (2 + 1.0)), 5)) = 0.000823
(1.0 / 7) * (pow(((2 - 1.0) / (2 + 1.0)), 7)) = 0.000065
(1.0 / 9) * (pow(((2 - 1.0) / (2 + 1.0)), 9)) = 0.000006
(1.0 / 11) * (pow(((2 - 1.0) / (2 + 1.0)), 11)) = 0.000001
(1.0 / 13) * (pow(((2 - 1.0) / (2 + 1.0)), 13)) = 0.000000
(1.0 / 15) * (pow(((2 - 1.0) / (2 + 1.0)), 15)) = 0.000000
(1.0 / 17) * (pow(((2 - 1.0) / (2 + 1.0)), 17)) = 0.000000
(1.0 / 19) * (pow(((2 - 1.0) / (2 + 1.0)), 19)) = 0.000000
(1.0 / 21) * (pow(((2 - 1.0) / (2 + 1.0)), 21)) = 0.000000
and so on...
The floating point comparison is exact, so 10^-10
is not the same as 0.0
.
Basically, you should be comparing against some tolerable difference, say 10^-7
based on the number of decimals you're writing out, that can be accomplished as:
while(fabs(tmp) > 10e-7)
Don't use exact equality operations when dealing with floating point numbers. Although your number may look like 0
, it likely to be something like 0.00000000000000000000001
.
You'll see this if you use %.50f
instead of %f
in your format strings. The latter uses a sensible default for decimal places (6 in your case) but the former explicitly states you want a lot.
For safety, use a delta to check if it's close enough, such as:
if (fabs (val) < 0.0001) {
// close enough.
}
Obviously, the delta depends entirely on your needs. If you're talking money, 10-5 may be plenty. If you're a physicist, you should probably choose a smaller value.
Of course, if you're a mathematician, no inaccuracy is small enough :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With