How is the modulo operator implemented in the HotSpot JVM?

后端 未结 3 1470
醉话见心
醉话见心 2021-01-22 21:21

I understand that the modulus operation can be optimised using a little & wise magic where the divisor is a power of 2...

  • and presuma
相关标签:
3条回答
  • 2021-01-22 21:45

    Yes, a modulo x % pow(2, n) can be achieved using x & ((1 << n) - 1)

    But the %-operator in java can give different results if x is negative, so blindly substituting one for the other can break code.

    When bit-addressing, masking etc. the &-variant is commonly used, as its semantically closer to what is used in assembler/C and signedness is usually not wanted/cared about in that case.

    As for if the JIT optimizes % to &, the answer is: it depends entirely on the JIT - and thats a moving target.

    In case x % y where y isn't a constant its pretty difficult to detect if y is a power of 2, so presumably that case isn't optimizable because detecting it is very difficult or impossible. If y is a constant, the JIT still has prove that x isn't negative - or insert a conditional similar to result = x < 0 ? x % y : x & (y-1). It may or may not do so, depending on JIT in question and also depending on the platform. At least Hotspot is known to use different optimizations for different processors (of the same ISA, namely AMD vs Intel) in some cases.

    0 讨论(0)
  • 2021-01-22 22:08

    Here is one sample code snippet

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

    Now if you see the compiled code of it You will see

    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- push a byte onto the stack as an integer value ie 103

    istore_1-Pops an int off the stack and stores it in local variable,in the current frame.

    and in 3: iconst_5 constant integer is pushed onto the stack

    istore_2 does the same as istore_1 just variable named changed.

    Then 5: iload_1 and 6:iload_2 both the variables are again pushed onto stack for operations

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

    Now how does Remainder operators works. It's Pops two ints(value of a and b) off the operand stack, divides a by b , computes the remainder and pushes the int remainder back onto the stack. The remainder is (b - ((a / b) * b)). This is what is used by the % operator in Java.

    0 讨论(0)
  • 2021-01-22 22:09

    I spent some time on this very question, writing this blog post with all the details.

    In short:

    • The HotSpot JDK 1.8 irem (mod int) is ~20% slower than the n & (pow2-1) trick
    • The HotSpot JDK 1.8 frem (mod float) is 3x slower
    • You mileage varies based on JIT passes, so the benefit for Int's is minimal

    So, there is a clear benefit to not do mod on Doubles, and you might get some benefit with Natural Integer Dividends and power of 2 Divisors.

    0 讨论(0)
提交回复
热议问题