我遇到了浮点数精度不精确的情况。正如我在下面作为我的代码的简化版本所示,我在等效场景中计算总和,并且在最后的小数中我得到不同的值。这与Is floating point math broken。
有关我想知道是否有办法解决这个问题,例如某种截断?
s1 = zero(Float64)
s = zero(Float64)
for a in 1:10000
for k in 1:4
temp=log(1e-5)
s1+=temp
s +=temp
end
end
s2 = zero(Float64)
for a in 1:10000
for k in 1:4
temp = log(1e-5)
s2+=temp
s+=temp
end
end
s1+s2 == s ###FALSE
s < s1+s2 ###TRUE
答案 0 :(得分:4)
浮点加法不是associative:改变加法的顺序可能会因中间舍入而产生微妙的不同结果。
你可以做几件事:
sum_kbn
: julia> sum_kbn(log(1e-5) for a = 1:10000, k = 1:4)
-460517.01859880914
isapprox
(也可以通过中缀≈
获得)。这会分别接受atol
和rtol
个可选参数来指定绝对和相对容差。 s1+s2 ≈ s
答案 1 :(得分:2)
Float64表示IEEE 754格式的数字。在64位中,尾数占据52位。这意味着大约15个十进制数字的精度。
第一次循环后,s1
和s
应该相同。
差异发生在第二个循环体中。 temp
中的数字始终相同。第一次进入第二个循环的循环体时,s
几乎为temp * 40000.0
。将temp
添加到s
时,会导致temp
的最后4.5位数字丢失。这是差异的原因,因为s2
将为零,添加temp
将使用temp
的所有数字。
顺便说一句,s,s1+s2
中没有一个(编程)与temp * 80000.0
相同(数学上所有3个数字都应该相同)
因此,为减少数字错误,请遵守规则
a / b
(a = abs(A), b = abs(B), a > b, b != 0
)这一切都不是julia的具体问题,它将在使用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)
输出
false
true
false
false
-921034.0371971375
-921034.0371976183
-921034.0371986133