Tim*_*ers 3 java bit-manipulation absolute-value
Math.abs(x)(由Oracle实施)的常规实现由
public static double abs(double a) {
return (a <= 0.0D) ? 0.0D - a : a;
}
Run Code Online (Sandbox Code Playgroud)
仅将数字符号的一位编码设置为零(或一位)是否更快?我想只有一个位编码数字的符号,并且它总是相同的位,但是我可能是错的。
还是我们的计算机通常不适合使用原子指令对单个位进行操作?
如果可以更快地实施,您能给出吗?
编辑:
已经向我指出Java代码是平台无关的,因此它不能依赖于单机的原子指令是什么。但是,为了优化代码,JVM热点优化器确实考虑了计算机的具体情况,并且可能会应用正在考虑的最优化方法。
但是,通过一个简单的测试,我发现至少在我的机器上,该Math.abs功能似乎并未针对单个原子指令进行优化。我的代码如下:
long before = System.currentTimeMillis();
int o = 0;
for (double i = 0; i<1000000000; i++)
if ((i-500)*(i-500)>((i-100)*2)*((i-100)*2)) // 4680 ms
o++;
System.out.println(o);
System.out.println("using multiplication: "+(System.currentTimeMillis()-before));
before = System.currentTimeMillis();
o = 0;
for (double i = 0; i<1000000000; i++)
if (Math.abs(i-500)>(Math.abs(i-100)*2)) // 4778 ms
o++;
System.out.println(o);
System.out.println("using Math.abs: "+(System.currentTimeMillis()-before));
Run Code Online (Sandbox Code Playgroud)
这给了我以下输出:
234
using multiplication: 4985
234
using Math.abs: 5587
Run Code Online (Sandbox Code Playgroud)
假设乘法是通过原子指令执行的,那么至少在我的机器上,JVM热点优化器似乎并未将Math.abs功能优化为单个指令操作。
我的第一个想法是,这是由于NaN(非数字)值所致,即,如果输入为NaN原值,则应返回该值而无需进行任何更改。但是,这似乎不是必需的,因为harold的测试表明JVM的内部优化不能保留NaN的符号(除非您使用StrictMath)。
Math.abs 的文档说:
换句话说,结果与表达式的值相同:
Double.longBitsToDouble((Double.doubleToLongBits(a)<<1)>>>1)
因此,此类的开发人员知道位操作的选项,但他们决定反对。
很可能是因为优化此Java代码没有意义。在大多数环境中,热点优化器一旦在热点中遇到,便会将其调用替换为适当的FPU指令。这发生在许多java.lang.Math方法以及Integer.rotateLeft类似方法中。它们可能具有纯Java实现,但是如果CPU有针对它的指令,它将由JVM使用。