我今天才注意到Math.fma(a, b, c)Java 9 的存在,它计算a*b + c
(for double和floatvalues).
返回三个参数的融合乘法加法; 也就是说,返回与第三个参数相加的前两个参数的精确乘积,然后将其舍入一次到最近的float.使用舍入到最近的偶数舍入模式完成舍入.相反,如果a*b + c被评估为常规浮点表达式,则涉及两个舍入误差,第一个用于乘法运算,第二个用于加法运算.
因此看起来它通过进行1舍入而不是2来提高准确性.这是正确的吗?那是有条件的CPU的能力,或者我们可以指望的是始终?
我猜它可能是使用特殊的CPU指令实现的.是这样的吗?如果是这样,我们还可以期待性能优势吗?我有兴趣了解当前平台/ CPU的实际好处,以及假设的未来收益.
编辑(试图让它变得不那么宽泛):我不是在寻找非常详细的答案:是/否对于纠正/确认我的理解的几个项目,加上一些指示,对我来说就足以标记答案了被接受了.我对准确性和性能方面都非常感兴趣,我认为它们在一起......
gez*_*eza 13
是的,FMA提高准确性的原因就是你所说的.
如果可用,JVM使用FMA CPU指令.但是,到处都没有FMA.例如,Haswell之前的Intel x86 CPU没有它.这意味着大多数Intel CPU目前没有FMA.
如果CPU FMA不可用,Java使用一个非常慢的解决方案:它使用FMA java.math.BigDecimal(这是当前的解决方案 - 它可能会在未来发生变化,但我敢打赌,与CPU FMA相比,它总是会变慢).
我正在使用第5代i7.当我做:
sysctl -n machdep.cpu.brand_string
Run Code Online (Sandbox Code Playgroud)
我可以看到我的cpu是Intel(R) Core(TM) i7-5557U CPU @ 3.10GHz,并且cu支持FMA,你可以看到:
sysctl -a | grep machdep.cpu | grep FMA
Run Code Online (Sandbox Code Playgroud)
结果我得到了一个存在这个String的行.现在让我们看看JVM是否实际使用了它.
这些方法(一个用于double和一个用于float)注释,@HotSpotIntrinsicCandidate这意味着JIT可以用实际的CPU本机指令替换它们 - 如果这样可用,但这意味着该方法必须足够热 - 多次调用并且这是依赖于JVM的事情.
我试图通过以下方式模拟:
public static void main(String[] args) {
double result = 0;
for (int i = 0; i < 50_000; ++i) {
result = result + mine(i);
}
System.out.println(result);
}
private static float mine(int x) {
return Math.fma(x, x, x);
}
Run Code Online (Sandbox Code Playgroud)
我用以下方式运行:
java -XX:+UnlockDiagnosticVMOptions
-XX:+PrintInlining
-XX:+PrintIntrinsics
-XX:CICompilerCount=2
-XX:+PrintCompilation
org.so/FMATest
Run Code Online (Sandbox Code Playgroud)
那里会有很多行,但其中一行是:
@ 6 java.lang.Math::fma (12 bytes) (intrinsic)
Run Code Online (Sandbox Code Playgroud)
这意味着JVM确实使用了FMA指令的内在方法.
| 归档时间: |
|
| 查看次数: |
979 次 |
| 最近记录: |