平均函数不正确的值

Mean function incorrect value

我有一个包含相同条目的 80 元素数组:176.01977965813853

如果我使用均值函数,我将得到值 176.01977965813842

这是为什么?


这是一个最小的工作示例:

using Statistics
arr = fill(176.01977965813853, 80)

julia> mean(arr)
176.01977965813842

我希望这个 return 176.01977965813853

这些只是预期的浮点错误。但是如果你需要非常精确的求和,你可以使用更复杂(和昂贵)的求和方案:

julia> using KahanSummation
[ Info: Precompiling KahanSummation [8e2b3108-d4c1-50be-a7a2-16352aec75c3]

julia> sum_kbn(fill(176.01977965813853, 80))/80
176.01977965813853

参考:Wikipedia

我理解的问题可以复现如下:

using Statistics
arr = fill(176.01977965813853, 80)

julia> mean(arr)
176.01977965813842

原因是 julia 默认以 64 位精度执行所有浮点运算(即 Float64 类型)。 Float64s 不能表示任何实数。每个浮点数之间有一个有限的步长,当您对它们进行算术运算时会产生舍入误差。这些舍入误差通常没什么大碍,但如果您不小心,它们可能会造成灾难性后果。例如:

julia> 1e100 + 1.0 - 1e100
0.0

也就是说,如果我这样做 10^100 + 1 - 10^100 我得到零!如果你想得到由浮点运算引起的误差的上限,我们可以使用 IntervalArithmetic.jl:

using IntervalArithmetic

julia> 1e100 + interval(1.0) - 1e100
[0, 1.94267e+84]

也就是说操作1e100 + 1.0 - 1e100至少等于0.0,最多等于1.94*10^84,所以误差范围很大!

我们可以为您感兴趣的操作做同样的事情,

arr = fill(interval(176.01977965813853), 80);

julia> mean(arr)
[176.019, 176.02]

julia> mean(arr).lo
176.019779658138

julia> mean(arr).hi
176.0197796581391

表示 实际 平均值可能至少 176.019779658138 或最多 176.0197796581391,但由于浮点数错误!所以在这里,Float64给出的答案最多有10^-13%的误差,其实是很小的。

如果这些是不可接受的错误界限怎么办?使用更精确!您可以使用 big 字符串宏来获取任意精度数字文字:

arr = fill(interval(big"176.01977965813853"), 80);

julia> mean(arr).lo
176.0197796581385299999999999999999999999999999999999999999999999999999999999546

julia> mean(arr).hi
176.019779658138530000000000000000000000000000000000000000000000000000000000043

该计算是使用 256 位精度完成的,但您可以使用 setprecision 函数获得更高的精度:

setprecision(1000)
arr = fill(interval(big"176.01977965813853"), 80);

julia> mean(arr).lo
176.019779658138529999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999599

julia> mean(arr).hi
176.019779658138530000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000579

请注意,与 Float64s 相比,任意精度算法 sloooow,因此通常最好只使用任意精度算法来验证您的结果,以确保您在您想要的精度范围内重新收敛到一个好的结果。