RFR (S) 8136500: Integer/Long getChars and stringSize should be more idiomatic

Ulf Ulf.Zibis at CoSoCo.de
Tue Nov 24 16:50:11 UTC 2015


Hi,

Am 24.11.2015 um 12:07 schrieb Aleksey Shipilev:
> Thanks for reviews, Ivan, John, Sherman and Paul!
>
> I am pushing this change now.

I know, I'm late, but have you ever tried? :

     static void getChars(int i, int index, byte[] buf) {
         // int q, r;        // superfluous
         // int charPos = index;     // superfluous
         boolean negative = i < 0;

         // Generate two digits per iteration      // q and r are not needed outside loop
         for (int q, i = negative ? i : -i; <= -100; i = q) {
             q = i / 100;
             byte r = (byte)((q * 100 - i) & 0x7F);
             // byte allows the compiler to use byte wide addressing opcodes
             // which have smaller footprint and are potentially faster
             // .. & 0x7F may additionally save negative bound check
             buf[(byte)(--index & 0x7F)] = DigitOnes[r];
             buf[(byte)(--index & 0x7F)] = DigitTens[r];
         }

         // We know there are at most two digits left at this point.
         byte q = (byte)i / 10;
         buf[(byte)(--index & 0x7F)] = (byte)(q * 10 - i +'0');

         // Whatever left is the remaining digit.
         if (q < 0) {
             buf[(byte)(--index & 0x7F)] = (byte)('0' - q);
         }
         if (negative) {
             buf[(byte)(--index & 0x7F)] = (byte)'-';
         }
     }

Additionally may try this:
(saves some calculations, but adds array access, only 1 for more frequent i < 10, otherwise 2)
         // We know there are at most two digits left at this point.
         byte r = (byte)(-i & 0x7F);
         buf[(byte)(--index & 0x7F)] = DigitOnes[r];

         // Whatever left is the remaining digit.
         if (r >= 10) {
             buf[(byte)(--index & 0x7F)] = DigitTens[r];
         }
         if (negative) {
             buf[(byte)(--index & 0x7F)] = (byte)'-';
         }


> 2)
> The lookup tables DigitTens and DigitOnes are always used together.
> Packing them in an one table can save us one array access for the price of little arithmetic.
>
>     static final int[] TwoDigits = {
>         ('0'<<16)+'0', ('0'<<16)+'1', ('0'<<16)+'2', ('0'<<16)+'3', ('0'<<16)+'4',
>         ('0'<<16)+'5', ('0'<<16)+'6', ('0'<<16)+'7', ('0'<<16)+'8', ('0'<<16)+'9',
>
> ...
>             int twoDig = TwoDigits[r];
>             buf[--charPos] = (byte)twoDig;
>             buf[--charPos] = (byte)(twoDig >> 16);
> ...

This could be done faster if using 1 "Unsafe putChar/Short()" instead 2 buf[--charPos] + shift.
... and better use char/short[] to save footprint and the compiler calculating the table offset with 
charPos<<1.

Alternatively use byte[] TwoDigits = useInternalCompactByteArrayOfString("00010203040506070809....")

-Ulf




More information about the core-libs-dev mailing list