我在几篇博客中读到,在Java模数/提醒操作符中比按位-EN慢。所以,我编写了以下程序进行测试。
public class ModuloTest {
public static void main(String[] args) {
final int size = 1024;
int index = 0;
long start = System.nanoTime();
for(int i = 0; i < Integer.MAX_VALUE; i++) {
getNextIndex(size, i);
}
long end = System.nanoTime();
System.out.println("Time taken by Modulo (%) operator --> " + (end - start) + "ns.");
start = System.nanoTime();
final int shiftFactor = size - 1;
for(int i = 0; i < Integer.MAX_VALUE; i++) {
getNextIndexBitwise(shiftFactor, i);
}
end = System.nanoTime();
System.out.println("Time taken by bitwise AND --> " + (end - start) + "ns.");
}
private static int getNextIndex(int size, int nextInt) {
return nextInt % size;
}
private static int getNextIndexBitwise(int size, int nextInt) {
return nextInt & size;
}
}
但在我的运行时环境(MacBook Pro 2.9GHz i7,8GB RAM,JDK 1.7.0_51)中,我看到了其他情况。按位-AND明显更慢,实际上比余数运算符慢两倍。
如果有人可以帮助我了解这是出于预期的行为还是我做错了什么,我将不胜感激?
谢谢, NIRANJAN
答案 0 :(得分:4)
你的代码按比例报告 - 并且在我尝试过的每台Mac上都快得多,包括Java 6和Java 7.我怀疑你的机器上的第一部分测试恰好与系统上的其他活动一致。您应该多次尝试运行测试,以验证您没有看到基于此的扭曲。 (我会把它留作'评论'而不是'答案',但显然你需要50点声望 - 如果你问我,那就太傻了。)
答案 1 :(得分:1)
这个例子特别会给你一个错误的结果。此外,我相信任何用2的幂计算模数的程序都会比按位AND快。
原因:当你使用N%X,其中X是k的2次幂时,只有最后k位被认为是模数,而在按位AND运算符的情况下,运行时实际上必须访问每个有问题的数字。
另外,我想指出热点JVM优化类似性质的重复计算(其中一个例子可以是分支预测等)。在你的情况下,使用模数的方法只返回数字的最后10位,因为1024是2的10次幂。
尝试使用一些素数值作为大小并检查相同的结果。
免责声明:微基准测试不算好。
答案 2 :(得分:1)
这种方法遗漏了什么吗?
public static void oddVSmod(){
float tests = 100000000;
oddbit(tests);
modbit(tests);
}
public static void oddbit(float tests){
for(int i=0; i<tests; i++)
if((i&1)==1) {System.out.print(" "+i);}
System.out.println();
}
public static void modbit(float tests){
for(int i=0; i<tests; i++)
if((i%2)==1) {System.out.print(" "+i);}
System.out.println();
}
有了这个,我使用netbeans内置的分析器(高级模式)来运行它。我将var测试设置为10X10 ^ 8,并且每次都显示模数比按位快。
答案 3 :(得分:1)
对于初学者来说,逻辑连接技巧仅适用于自然数红利和2个除数的幂。因此,如果您需要负红利,浮动或2的非权力,请使用默认的%
运营商。
My tests(使用JIT预热和1M随机迭代),在具有大量核心和总线负载的ram的i7上显示<按>按比例增加<20>更好的性能。这可以非常运行,具体取决于进程调度程序如何运行代码。
答案 4 :(得分:0)
谢谢大家的宝贵意见。
@pamphlet:非常感谢您的关注,但负面评论对我很好。我承认我没有按照AndyG的建议进行适当的测试。 AndyG本来可以使用更柔和的音调,但是没关系,有时负片有助于看到积极因素。 :)
也就是说,我改变了我的代码(如下所示),我可以多次运行该测试。
public class ModuloTest {
public static final int SIZE = 1024;
public int usingModuloOperator(final int operand1, final int operand2) {
return operand1 % operand2;
}
public int usingBitwiseAnd(final int operand1, final int operand2) {
return operand1 & operand2;
}
public void doCalculationUsingModulo(final int size) {
for(int i = 0; i < Integer.MAX_VALUE; i++) {
usingModuloOperator(1, size);
}
}
public void doCalculationUsingBitwise(final int size) {
for(int i = 0; i < Integer.MAX_VALUE; i++) {
usingBitwiseAnd(i, size);
}
}
public static void main(String[] args) {
final ModuloTest moduloTest = new ModuloTest();
final int invocationCount = 100;
// testModuloOperator(moduloTest, invocationCount);
testBitwiseOperator(moduloTest, invocationCount);
}
private static void testModuloOperator(final ModuloTest moduloTest, final int invocationCount) {
for(int i = 0; i < invocationCount; i++) {
final long startTime = System.nanoTime();
moduloTest.doCalculationUsingModulo(SIZE);
final long timeTaken = System.nanoTime() - startTime;
System.out.println("Using modulo operator // Time taken for invocation counter " + i + " is " + timeTaken + "ns");
}
}
private static void testBitwiseOperator(final ModuloTest moduloTest, final int invocationCount) {
for(int i = 0; i < invocationCount; i++) {
final long startTime = System.nanoTime();
moduloTest.doCalculationUsingBitwise(SIZE);
final long timeTaken = System.nanoTime() - startTime;
System.out.println("Using bitwise operator // Time taken for invocation counter " + i + " is " + timeTaken + "ns");
}
}
}
我以互相排斥的方式致电testModuloOperator()
和testBitwiseOperator()
。结果与按位比模运算符更快的想法一致。我运行了100次计算并记录了执行时间。然后删除前五个和最后五个录音,并使用休息来计算平均值。时间。以下是我的测试结果。
8388.89ns
。722.22ns
。请说明我的方法是否正确。
再次感谢。 NIRANJAN