Для скаляров оператор \
(решение линейной системы) эквивалентен оператору деления /
. Похоже по производительности?
Я спрашиваю, потому что сейчас в моем коде есть строка вроде
x = (1 / alpha) * averylongfunctionname(input1, input2, input3)
Визуально важно, чтобы деление на alpha
происходило слева, поэтому я рассматриваю возможность замены этого на
x = alpha \ averylongfunctionname(input1, input2, input3)
Как лучше всего поступить в этой ситуации с точки зрения стиля и производительности?
Вот некоторые озадачивающие результаты тестов:
julia> using BenchmarkTools
[ Info: Precompiling BenchmarkTools [6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf]
julia> @btime x[1]\sum(x) setup=(x=rand(100))
15.014 ns (0 allocations: 0 bytes)
56.23358979466163
julia> @btime (1/x[1]) * sum(x) setup=(x=rand(100))
13.312 ns (0 allocations: 0 bytes)
257.4552413802698
julia> @btime sum(x)/x[1] setup=(x=rand(100))
14.929 ns (0 allocations: 0 bytes)
46.25209548841374
Все они примерно одинаковы, но я удивлен, что подход (1 / x) * foo
имеет лучшую производительность.
Скалярные
/
и\
действительно должны иметь одинаковое значение и производительность. Определим эти две тестовые функции:Затем мы видим, что они производят идентичный код LLVM:
И тот же машинный код тоже. Я не уверен, что вызывает различия в
@btime
результатах, но я почти уверен, что разница между/
и\
является иллюзией, а не реальностью.Что касается
x*(1/y)
, он не вычисляет то же самое, чтоx/y
: он будет потенциально менее точным, поскольку при вычислении1/y
выполняется округление, а затем это округленное значение умножается наx
, которое также округляется. Например:Поскольку при делении с плавающей запятой гарантируется правильное округление, выполнение деления напрямую всегда будет более точным. Однако, если делитель используется во многих итерациях цикла, вы можете получить ускорение, переписав вычисление таким образом, поскольку умножение с плавающей запятой обычно быстрее, чем деление (хотя время на моем текущем компьютере этого не показывает). Однако имейте в виду, что это приводит к потере точности, и, если делитель не используется совместно, все равно будет потеря точности и никакого увеличения производительности.
Спасибо. Есть какие-нибудь мысли по поводу стиля? — person Max; 13.12.2020
Мне нравится использовать
alpha \ (longer expression)
, но некоторых это может сбивать с толку, поэтому это кажется немного субъективным. Я бы посоветовал использовать его, если он вам нравится, и он станет понятнее. — person Max; 13.12.2020Я думаю, что лучший выбор —
(1/x)*foo
по двум причинам: