Today, I came across quite strange problem. I needed to calculate string length of a number, so I came up with this solution
// say the number is 1000
(int)(log(1000)/log(10)) + 1
This is based on mathematical formula
log
10x = log
nx/log
n10
(explained here)
But I found out, that in C,
(int)(log(1000)/log(10)) + 1
is NOT equal to
(int) log10(1000) + 1
but it should be.
I even tried the same thing in Java with this code
(int) (Math.log(1000) / Math.log(10)) + 1
(int) Math.log10(1000) + 1
but it behave the same wrong way.
The story continues. After executing this code
for (int i = 10; i < 10000000; i *= 10) {
System.out.println(((int) (Math.log10(i)) + 1) +
" " + ((int) (Math.log(i) / Math.log(10)) + 1));
}
I get
2 2
3 3
4 3 // here second method produces wrong result for 1000
5 5
6 6
7 6 // here again
So the bug seems to occur on every multiple of 1000.
I showed this to my C teacher, and he said that it might be caused by some type conversion error during log division, but he didn't know why.
So my questions are
(int) (Math.log(1000) / Math.log(10)) + 1
equal to (int) Math.log10(1000) + 1
, while it should be, according to the math.edit: It is not rounding error, because
Math.floor(Math.log10(i)) + 1
Math.floor(Math.log(i) / Math.log(10)) + 1
produce same, wrong output
2 2
3 3
4 3
5 5
6 6
7 6
edit2: I have to round down, because I want to know the number of digits.
log10(999) + 1 = 3.9995654882259823
log10(1000) + 1 = 4.0
If I just round, I get same result (4), which is wrong for 999, because it has 3 digits.
You provided the code snippet
for (int i = 10; i < 10000000; i *= 10) {
System.out.println(((int) (Math.log10(i)) + 1) +
" " + ((int) (Math.log(i) / Math.log(10)) + 1));
}
to illustrate your question. Just remove the casts to int
and run the loop again. You will receive
2.0 2.0
3.0 3.0
4.0 3.9999999999999996
5.0 5.0
6.0 6.0
7.0 6.999999999999999
which immediately answers your question. As tliff already argued, the casts cut off the decimals instead of rounding properly.
EDIT: You updated your question to use floor()
, but like casting floor()
will round down and therefore drop the decimals!
The log operation is a Transcendental Function. The best a computer can do to evaluate the result is to use an Algebraic Function which approximates the required operation. The accuracy of the result is dependent on the algorithm the computer uses (this could be the microcode in the FPU). On the Intel FPU, there are settings the affect the precision of the various transcendental functions (trig functions are also transcendental) and the FPU specifications will detail the level of accuracy of the various algorithms used.
So, in addition to the rounding errors mentioned above, there is also an accuracy issue as well since computed log(x) may not be equal to actual log(x).
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