Проблема, насколько я понимаю, может быть воспроизведена следующим образом:
using Statistics
arr = fill(176.01977965813853, 80)
julia> mean(arr)
176.01977965813842
Причина этого заключается в том, что Юлия выполняет всю арифметику с плавающей запятой с 64-битной точностью по умолчанию (т. Е. Тип Float64
). Float64
s не может представлять любое действительное число. Существует конечный шаг между каждым числом с плавающей запятой, и ошибки округления возникают, когда вы выполняете арифметику с ними. Эти ошибки округления обычно хороши, но если вы не будете осторожны, они могут быть катастрофическими. Например:
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
Обратите внимание, что арифметика произвольной точности равна sloooow по сравнению с Float64
с, поэтому обычно лучше всего использовать арифметику произвольной точности для проверки результатов, чтобы убедиться, что вы сходитесь кхороший результат в пределах вашей желаемой точности.