这种用法在编写循环时很常见。
我想知道是否i >=0
需要更多的 CPU 周期,因为greater than OR equal to
与i > -1
. 是否已知一个比另一个更好,如果是,为什么?
这种用法在编写循环时很常见。
我想知道是否i >=0
需要更多的 CPU 周期,因为greater than OR equal to
与i > -1
. 是否已知一个比另一个更好,如果是,为什么?
这是不正确的。JIT 将把这两个测试作为一个单一的机器语言指令来实现。
并且CPU时钟周期数不是由比较次数决定为零还是-1,因为CPU应该做一次比较,并设置标志来指示比较的结果是<、>还是=。
在某些处理器上,其中一条指令可能会更有效,但这种微优化几乎总是不值得做的。(也有可能 JIT - 或 javac - 实际上会为两个测试生成相同的指令。)
相反,与零的比较(包括非严格)减少了一条 CPU 指令。x86 体系结构支持任何算术或加载操作后的条件跳转。体现在Java字节码指令集中,有一组指令比较栈顶的值并跳转:ifeq
///// 。(查看完整列表)。比较需要额外的操作(将常量加载到堆栈上)。ifgt
ifge
iflt
ifle
ifne
-1
iconst_m1
-1
这是两个具有不同比较的循环:
@GenerateMicroBenchmark
public int loopZeroCond() {
int s = 0;
for (int i = 1000; i >= 0; i--) {
s += i;
}
return s;
}
@GenerateMicroBenchmark
public int loopM1Cond() {
int s = 0;
for (int i = 1000; i > -1; i--) {
s += i;
}
return s;
}
第二个版本长一个字节:
public int loopZeroCond();
Code:
0: iconst_0
1: istore_1
2: sipush 1000
5: istore_2
6: iload_2
7: iflt 20 //
10: iload_1
11: iload_2
12: iadd
13: istore_1
14: iinc 2, -1
17: goto 6
20: iload_1
21: ireturn
public int loopM1Cond();
Code:
0: iconst_0
1: istore_1
2: sipush 1000
5: istore_2
6: iload_2
7: iconst_m1 //
8: if_icmple 21 //
11: iload_1
12: iload_2
13: iadd
14: istore_1
15: iinc 2, -1
18: goto 6
21: iload_1
22: ireturn
它在我的机器上性能略高(令我惊讶。我希望 JIT 将这些循环编译成相同的程序集。)
Benchmark Mode Thr Mean Mean error Units
t.LoopCond.loopM1Cond avgt 1 0,319 0,004 usec/op
t.LoopCond.loopZeroCond avgt 1 0,302 0,004 usec/op
在合理的情况下与零进行比较。