Why is 2 * (i * i) faster than 2 * i * i in Java?

前端 未结 10 731
一生所求
一生所求 2020-12-22 14:43

The following Java program takes on average between 0.50 secs and 0.55 secs to run:

public static void main(String[] args) {
    long startTime = System.nano         


        
10条回答
  •  误落风尘
    2020-12-22 15:04

    Byte codes: https://cs.nyu.edu/courses/fall00/V22.0201-001/jvm2.html Byte codes Viewer: https://github.com/Konloch/bytecode-viewer

    On my JDK (Windows 10 64 bit, 1.8.0_65-b17) I can reproduce and explain:

    public static void main(String[] args) {
        int repeat = 10;
        long A = 0;
        long B = 0;
        for (int i = 0; i < repeat; i++) {
            A += test();
            B += testB();
        }
    
        System.out.println(A / repeat + " ms");
        System.out.println(B / repeat + " ms");
    }
    
    
    private static long test() {
        int n = 0;
        for (int i = 0; i < 1000; i++) {
            n += multi(i);
        }
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            n += multi(i);
        }
        long ms = (System.currentTimeMillis() - startTime);
        System.out.println(ms + " ms A " + n);
        return ms;
    }
    
    
    private static long testB() {
        int n = 0;
        for (int i = 0; i < 1000; i++) {
            n += multiB(i);
        }
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            n += multiB(i);
        }
        long ms = (System.currentTimeMillis() - startTime);
        System.out.println(ms + " ms B " + n);
        return ms;
    }
    
    private static int multiB(int i) {
        return 2 * (i * i);
    }
    
    private static int multi(int i) {
        return 2 * i * i;
    }
    

    Output:

    ...
    405 ms A 785527736
    327 ms B 785527736
    404 ms A 785527736
    329 ms B 785527736
    404 ms A 785527736
    328 ms B 785527736
    404 ms A 785527736
    328 ms B 785527736
    410 ms
    333 ms
    

    So why? The byte code is this:

     private static multiB(int arg0) { // 2 * (i * i)
         
    
         L1 {
             iconst_2
             iload0
             iload0
             imul
             imul
             ireturn
         }
         L2 {
         }
     }
    
     private static multi(int arg0) { // 2 * i * i
         
    
         L1 {
             iconst_2
             iload0
             imul
             iload0
             imul
             ireturn
         }
         L2 {
         }
     }
    

    The difference being: With brackets (2 * (i * i)):

    • push const stack
    • push local on stack
    • push local on stack
    • multiply top of stack
    • multiply top of stack

    Without brackets (2 * i * i):

    • push const stack
    • push local on stack
    • multiply top of stack
    • push local on stack
    • multiply top of stack

    Loading all on the stack and then working back down is faster than switching between putting on the stack and operating on it.

提交回复
热议问题