A Float64 represents a number in the IEEE 754 format. Out of the 64 bit the mantissa occupies 52 bits. This means a precision of about 15 decimal digits.
After your first loop, s1
and s
should be the same.
The difference happens in the second loop body. The number in temp
is always the same. s
is nearly temp * 40000.0
when entering the first time the loop body of the second loop. When adding temp
to s
this causes to loose the last 4.5 digits of temp
. This is the cause of the differences since s2
will be zero and adding temp
will use all digits of temp
.
by the way, none of s,s1+s2
will be (programmatically) the same as temp * 80000.0
(mathematically all 3 numbers should be the same)
So for reducing numeric errors obey the rules
- prefer multiplications, they retain precision
- adding numbers are more precise the more they are equal. You loose precision in the order of
a / b
(while a = abs(A), b = abs(B), a > b, b != 0
)
- subtracting numbers looses precision the more they are equal. You loose the precision in the order of leading common digits, or more exactly bits.
This all is no specific problem of julia, it will happen in all languages which using IEEE 754 (C/C++ double, Java double, Julia Float64,..)
s1 = zero(Float64)
s = zero(Float64)
for a in 1:40000
temp=log(1e-5)
s1+=temp
s +=temp
end
s2 = zero(Float64)
for a in 1:40000
temp = log(1e-5)
s2+=temp
s+=temp
end
sm = 80000.0 * log(1e-5);
println(s1+s2 == s)
println(s < s1+s2)
println(s == sm)
println(s1+s2 == sm)
println(s1+s2)
println(sm)
println(s)
outputs
false
true
false
false
-921034.0371971375
-921034.0371976183
-921034.0371986133