JDK-8189785 : JDK method:java.lang.Long.numberOfLeadingZeros(long) need to be optimized
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 9
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • Submitted: 2017-10-13
  • Updated: 2018-02-02
  • Resolved: 2017-10-23
Related Reports
Duplicate :  
Description
A DESCRIPTION OF THE REQUEST :
the original code is:
public static int numberOfLeadingZeros(long i) {
        // HD, Figure 5-6
         if (i == 0)
            return 64;
        int n = 1;
        int x = (int)(i >>> 32);
        if (x == 0) { n += 32; x = (int)i; }
        if (x >>> 16 == 0) { n += 16; x <<= 16; }
        if (x >>> 24 == 0) { n +=  8; x <<=  8; }
        if (x >>> 28 == 0) { n +=  4; x <<=  4; }
        if (x >>> 30 == 0) { n +=  2; x <<=  2; }
        n -= x >>> 31;
        return n;
    }

I think it can be optimized,should add following condition logic:
if (i < 0)
        return 0;

the fully optimized code is:
public static int numberOfLeadingZeros(long i) {
        // HD, Figure 5-6
         if (i == 0)
            return 64;
         if (i < 0)
            return 0;
        int n = 1;
        int x = (int)(i >>> 32);
        if (x == 0) { n += 32; x = (int)i; }
        if (x >>> 16 == 0) { n += 16; x <<= 16; }
        if (x >>> 24 == 0) { n +=  8; x <<=  8; }
        if (x >>> 28 == 0) { n +=  4; x <<=  4; }
        if (x >>> 30 == 0) { n +=  2; x <<=  2; }
        n -= x >>> 31;
        return n;
    }



JUSTIFICATION :
In some condition, for example, use -XX:DisableIntrinsic option disabled the intrinsic function, then the default java implementation code will be run. then the original code will be slower than the optimized code.


---------- BEGIN SOURCE ----------

public class TestForNumberOfLeadingZerosOfLong {
    
    public static void main(String[] args) {
        testLong();
    }

    public static void testLong() {
        long startTimeOfOptMethod = System.currentTimeMillis();
        for(long i=-1;i>Integer.MIN_VALUE;i--) {
            optNumberOfLeadingZeros(i);
        }
        System.out.println("optimized method took time in millis:" + (System.currentTimeMillis() - startTimeOfOptMethod));
        
        long startTimeOfOriginMethod = System.currentTimeMillis();
        for(long i=-1;i>Integer.MIN_VALUE;i--) {
            Long.numberOfLeadingZeros(i);
        }
        System.out.println("origin method took time in millis:" + (System.currentTimeMillis() - startTimeOfOriginMethod));
    }
    
    public static int optNumberOfLeadingZeros(long i) {
        // HD, Figure 5-6
         if (i == 0)
            return 64;
         if(i < 0) 
             return 0;
        int n = 1;
        int x = (int)(i >>> 32);
        if (x == 0) { n += 32; x = (int)i; }
        if (x >>> 16 == 0) { n += 16; x <<= 16; }
        if (x >>> 24 == 0) { n +=  8; x <<=  8; }
        if (x >>> 28 == 0) { n +=  4; x <<=  4; }
        if (x >>> 30 == 0) { n +=  2; x <<=  2; }
        n -= x >>> 31;
        return n;
    }
    
}

run the test class in cmd line with Intrinsic disabled:
java -XX:+UnlockDiagnosticVMOptions -XX:DisableIntrinsic=_numberOfLeadingZeros_l TestForNumberOfLeadingZerosOfLong

here is the test results from my own MacBook:
optimized method took time in millis:1510
origin method took time in millis:4360
---------- END SOURCE ----------


Comments
Closing as duplicate of JDK-8189230. The additional information has been added to that bug.
23-10-2017