如何在HotSpot JVM中实现模运算符?

时间:2015-04-24 09:53:34

标签: java optimization jit jvm-hotspot

我知道modulus operation可以使用一点 & 明智的魔法进行优化,其中除数是2的幂...

  • 并且可能这是JIT编译器的优化?

3 个答案:

答案 0 :(得分:3)

是的,使用x % pow(2, n)

可以实现模x & ((1 << n) - 1)

但是如果x是负数,那么java中的%-operator可以给出不同的结果,所以盲目地用一个代替另一个可能会破坏代码。

当位寻址,屏蔽等通常使用&amp; -variant时,因为它在语义上更接近于汇编程序/ C和签名中使用的内容,在这种情况下通常不需要/关心。

至于如果JIT将%优化为&amp;,答案是:它完全取决于JIT - 那就是一个移动的目标。

如果x % y其中y不是常数,如果y是2的幂,则非常难以检测到,因此可能该情况不可优化,因为检测它非常困难或不可能。如果y是常数,则JIT仍然证明x不是负数 - 或者插入类似于result = x < 0 ? x % y : x & (y-1)的条件。它可能会也可能不会这样,取决于所讨论的JIT,也取决于平台。至少Hotspot在某些情况下对不同的处理器(同一个ISA,即AMD vs Intel)使用不同的优化。

答案 1 :(得分:2)

我在这个问题上花了一些时间,用blog post写下所有细节。

简而言之:

  • HotSpot JDK 1.8 irem(mod int)比n & (pow2-1)技巧慢〜20%
  • HotSpot JDK 1.8 frem(mod浮动)慢3倍
  • 您的里程根据JIT通行证而有所不同,因此Int的优势很小

因此,对双打不做mod有明显的好处,你可以通过自然整数红利和2除数的力量获得一些好处。

答案 2 :(得分:-1)

以下是一个示例代码段

public class Test {

    public static void main(String[] args)  {
        int a=103;
        int b=5;
        int c=a%b;
        }
    }

现在,如果您看到它的编译代码,您将看到

public static void main(java.lang.String[]);
   flags: ACC_PUBLIC, ACC_STATIC
   Code:
     stack=2, locals=4, args_size=1
        0: bipush        103
        2: istore_1
        3: iconst_5
        4: istore_2
        5: iload_1
        6: iload_2
        7: irem
        8: istore_3
        9: return

bipush-将一个字节作为整数值(即103

)推入堆栈

istore_1 - 从堆栈中弹出一个int并将其存储在当前帧的本地变量中。

和3:iconst_5常量整数被压入堆栈

istore_2与istore_1相同,只是名为changed的变量。

然后5: iload_16:iload_2两个变量再次被压入堆栈以进行操作

now at 7:irem the remainder operator works which you are calling as modulo.

现在Remainder运算符是如何工作的。它从操作数堆栈中弹出两个整数(a和b的值),除以b,计算余数并将int余数推回堆栈。其余的是(b   - ((a / b)* b))。这是Java中%运算符使用的内容。