在Julia中使用“而不是`/`
对于标量,(求解线性系统)运算符等效于除法运算符/。性能相似吗?
我问是因为目前我的代码有一行
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 方法具有最佳性能。
回答
标量/和真正应该具有相同的含义和性能。让我们定义这两个测试函数:
f(a, b) = a / b
g(a, b) = b a
然后我们可以看到它们生成了相同的 LLVM 代码:
julia> @code_llvm f(1.5, 2.5)
; @ REPL[29]:1 within `f'
define double @julia_f_380(double %0, double %1) {
top:
; ? @ float.jl:335 within `/'
%2 = fdiv double %0, %1
; ?
ret double %2
}
julia> @code_llvm g(1.5, 2.5)
; @ REPL[30]:1 within `g'
define double @julia_g_382(double %0, double %1) {
top:
; ? @ operators.jl:579 within `'
; ?? @ float.jl:335 within `/'
%2 = fdiv double %0, %1
; ??
ret double %2
}
而且机器码也是一样的。我不确定是什么导致了@btime结果的差异,但我很确定/和之间的差异是一种错觉而不是真实的。
至于x*(1/y),这不会计算与 相同的事情x/y:它可能不太准确,因为在计算时进行了舍入1/y,然后将舍入的值乘以x,这也舍入。例如:
julia> 17/0.7
24.28571428571429
julia> 17*(1/0.7)
24.285714285714285
由于浮点除法保证被正确舍入,直接除法总是会更准确。但是,如果除数由许多循环迭代共享,您可以通过像这样重写计算来获得加速,因为浮点乘法通常比除法快(尽管我当前的计算机没有显示这一点)。但是请注意,这会损失准确性,并且如果不共享除数,仍然会损失准确性并且不会提高性能。