性能问题:最快为十六进制字符转换为Java中的数值方法是什么?转换为、数值、字符、最快

2023-09-11 00:03:50 作者:瘾

我想从字符重新presenting十六进制值转换(大写或小写),以字节,像

  0  - 大于0,1 - > 1,'A' - > 10,A - > 10,'F' - > 15等...
 

我会调用这个方法非常频繁,所以性能是非常重要的。有没有更快的方式比使用pre-初始化的HashMap<性格,字节> 得到的值

答案

看起来这是使用一个开关外壳和乔恩斯基特的直接计算解决方案之间的tossup - 开关情况下的解决方案似乎边出非常轻微,但 Greg的阵法胜出。这里有绩效考核的结果(以毫秒)的各种方法200,000,000运行:

  Character.getNumericValue:
8360

Character.digit将:
8453

HashMap的<性格,字节计算值:
15109

格雷格的阵列方法:
6656

JonSkeet直接法:
7344

开关:
7281
 

谢谢你们!

基准测试方法,code

超市办公Excel49个逆天实用功能,一看就会动画教程珍藏版

下面雅去,JonSkeet,你这个老对手。 ; - )

 公共类暂存器{

    私有静态最终诠释NUMBER_OF_RUNS = 2亿;

    静态字节水库;

    静态的HashMap<性格,字节>图=新的HashMap<性格,字节>(){{
        把(Character.valueOf('0'),Byte.valueOf((字节)0));
        把(Character.valueOf(1),Byte.valueOf((字节),1));
        放(Character.valueOf('2'),Byte.valueOf((字节)2));
        放(Character.valueOf('3'),Byte.valueOf((字节3)3));
        放(Character.valueOf('4'),Byte.valueOf((字节)4));
        放(Character.valueOf('5'),Byte.valueOf((字节)5));
        把(Character.valueOf(6),Byte.valueOf((字节)6));
        把(Character.valueOf('7'),Byte.valueOf((字节)7));
        把(Character.valueOf(8),Byte.valueOf((字节)8)​​);
        把(Character.valueOf('9'),Byte.valueOf((字节)9));
        放(Character.valueOf('a')的,Byte.valueOf((字节)10));
        把(Character.valueOf(B),Byte.valueOf((字节)11));
        把(Character.valueOf('C'),Byte.valueOf((字节)12));
        把(Character.valueOf(D),Byte.valueOf((字节)13));
        把(Character.valueOf(E),Byte.valueOf((字节)14));
        把(Character.valueOf('F'),Byte.valueOf((字节)15));
        把(Character.valueOf('A'),Byte.valueOf((字节)10));
        放(Character.valueOf('B'),Byte.valueOf((字节)11));
        把(Character.valueOf('C'),Byte.valueOf((字节)12));
        把(Character.valueOf(D),Byte.valueOf((字节)13));
        把(Character.valueOf(E),Byte.valueOf((字节)14));
        把(Character.valueOf(F),Byte.valueOf((字节)15));
    }};
    静态INT [] charValues​​ = {0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,-1,10, 11,第12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
                    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 ,10,11,12,13,14,15};
    静态的char [] CS =新的char [] {'0','1','2','3','4','5','6','7','8','9' ,A,B,C,D,E,F,A,B,C,D,E,F};

    公共静态无效的主要(字符串的args [])抛出异常{
        很长一段时间= System.currentTimeMillis的();
        的for(int i = 0; I< NUMBER_OF_RUNS;我++){
            RES = getNumericValue(我);
        }
        的System.out.println(Character.getNumericValue:);
        的System.out.println(System.currentTimeMillis的() - 时间);
        时间= System.currentTimeMillis的();
        的for(int i = 0; I< NUMBER_OF_RUNS;我++){
            RES = getDigit(我);
        }
        的System.out.println(Character.digit将:);
        的System.out.println(System.currentTimeMillis的() - 时间);
        时间= System.currentTimeMillis的();
        的for(int i = 0; I< NUMBER_OF_RUNS;我++){
            尝试 {
                RES = getValueFromArray(我);
            }赶上(抛出:IllegalArgumentException E){
            }
        }
        的System.out.println(阵列);
        的System.out.println(System.currentTimeMillis的() - 时间);
        时间= System.currentTimeMillis的();
        的for(int i = 0; I< NUMBER_OF_RUNS;我++){
            RES = getValueFromHashMap(我);
        }
        的System.out.println(HashMap的<性格,字节计算值:);
        的System.out.println(System.currentTimeMillis的() - 时间);
        时间= System.currentTimeMillis的();
        的for(int i = 0; I< NUMBER_OF_RUNS;我++){
            焦炭C = CS [我%cs.length]。
            RES = getValueFromComputeMethod(C);
        }
        的System.out.println(JonSkeet直接法:);
        的System.out.println(System.currentTimeMillis的() - 时间);
        时间= System.currentTimeMillis的();
        的for(int i = 0; I< NUMBER_OF_RUNS;我++){
            RES = getValueFromSwitch(我);

        }
        的System.out.println(切换);
        的System.out.println(System.currentTimeMillis的() - 时间);
    }

    私人静态字节getValueFromSwitch(int i)以{
        字节水库;
        焦炭CH = CS [我%cs.length]。
        开关(CH){
            情况下0:
                RES = 0;
                打破;
            情况1':
                RES = 1;
                打破;
            案2:
                RES = 2;
                打破;
            案3:
                RES = 3;
                打破;
            案4:
                RES = 4;
                打破;
            案5:
                RES = 5;
                打破;
            案6:
                RES = 6;
                打破;
            案7:
                RES = 7;
                打破;
            情况下8:
                RES = 8;
                打破;
            案9:
                RES = 9;
                打破;
            案一:
            情况下A:
                RES = 10;
                打破;
            案例'B':
            案例'B':
                RES = 11;
                打破;
            情况下C:
            情况下C:
                RES = 12;
                打破;
            情况下D:
            情况下D:
                RES = 13;
                打破;
            案E:
            案E:
                RES = 14;
                打破;
            案例'F':
            案例'F':
                RES = 15;
                打破;
            默认:
                抛出新的RuntimeException(未知的十六进制字符:+ CH);
        }
        返回水库;
    }

    私人静态字节getValueFromComputeMethod(字符C){
        字节的结果= 0;
        如果(c取代; ='0'和;&安培;℃下='9')
        {
            结果=(字节)(三 - '0');
        }
        如果(C> ='A'和;和C< ='F')
        {
            结果=(字节)(C  - 'A'+ 10);
        }
        如果(C> ='A'和;和C< =F)
        {
            结果=(字节)(C  - 'A'+ 10);
        }
        返回结果;
    }

    私人静态字节getValueFromHashMap(int i)以{
        返回map.get(Character.valueOf(CS [则i%cs.length])).byteValue();
    }

    私人静态字节getValueFromArray(int i)以{
        焦炭C = CS [我%cs.length]。
        如果(C<'0'|| c取代;'F'){
            抛出新抛出:IllegalArgumentException();
        }
        字节的结果=(字节)charValues​​ [C-'0'];
        如果(水库℃,){
            抛出新抛出:IllegalArgumentException();
        }
        返回结果;
    }

    私人静态字节getDigit(int i)以{
        返程(字节)Character.digit将(CS [我%cs.length],16);
    }

    私人静态字节getNumericValue(int i)以{
        返程(字节)Character.getNumericValue(CS [我%cs.length]);
    }

}
 

解决方案

一个preinitialised阵列会比一个HashMap快。事情是这样的:

 INT CharValues​​ [f的 - '0'+ 1] = {0,1,2,3,4,5,6,7,8,9,-1, -1,... -1,10,11,12,...};

如果(C<'0'|| c取代;'F'){
    抛出新抛出:IllegalArgumentException();
}
INT N = CharValues​​ [C-'0'];
如果(正℃,){
    抛出新抛出:IllegalArgumentException();
}
// N包含一个数字值
 

您应该基准,其他方法这个方法(如Jon飞碟双向的直接法)来确定,这将是最快的为您的应用程序。

I want to convert from char representing a hexadecimal value (in upper or lower case) to byte, like

'0'->0, '1' -> 1, 'A' -> 10, 'a' -> 10, 'f' -> 15 etc...

I will be calling this method extremely often, so performance is important. Is there a faster way than to use a pre-initialized HashMap<Character,Byte> to get the value from?

Answer

It seems like it's a tossup between using a switch-case and Jon Skeet's direct computing solution - the switch-case solution seems to edge out ever so slightly, though. Greg's array method wins out. Here are the performance results (in ms) for 200,000,000 runs of the various methods:

Character.getNumericValue:
8360

Character.digit:
8453

HashMap<Character,Byte>:
15109

Greg's Array Method:
6656

JonSkeet's Direct Method:
7344

Switch:
7281

Thanks guys!

Benchmark method code

Here ya go, JonSkeet, you old competitor. ;-)

public class ScratchPad {

    private static final int NUMBER_OF_RUNS = 200000000;

    static byte res;

    static HashMap<Character, Byte> map = new HashMap<Character, Byte>() {{
        put( Character.valueOf( '0' ), Byte.valueOf( (byte )0 ));
        put( Character.valueOf( '1' ), Byte.valueOf( (byte )1 ));
        put( Character.valueOf( '2' ), Byte.valueOf( (byte )2 ));
        put( Character.valueOf( '3' ), Byte.valueOf( (byte )3 ));
        put( Character.valueOf( '4' ), Byte.valueOf( (byte )4 ));
        put( Character.valueOf( '5' ), Byte.valueOf( (byte )5 ));
        put( Character.valueOf( '6' ), Byte.valueOf( (byte )6 ));
        put( Character.valueOf( '7' ), Byte.valueOf( (byte )7 ));
        put( Character.valueOf( '8' ), Byte.valueOf( (byte )8 ));
        put( Character.valueOf( '9' ), Byte.valueOf( (byte )9 ));
        put( Character.valueOf( 'a' ), Byte.valueOf( (byte )10 ));
        put( Character.valueOf( 'b' ), Byte.valueOf( (byte )11 ));
        put( Character.valueOf( 'c' ), Byte.valueOf( (byte )12 ));
        put( Character.valueOf( 'd' ), Byte.valueOf( (byte )13 ));
        put( Character.valueOf( 'e' ), Byte.valueOf( (byte )14 ));
        put( Character.valueOf( 'f' ), Byte.valueOf( (byte )15 ));
        put( Character.valueOf( 'A' ), Byte.valueOf( (byte )10 ));
        put( Character.valueOf( 'B' ), Byte.valueOf( (byte )11 ));
        put( Character.valueOf( 'C' ), Byte.valueOf( (byte )12 ));
        put( Character.valueOf( 'D' ), Byte.valueOf( (byte )13 ));
        put( Character.valueOf( 'E' ), Byte.valueOf( (byte )14 ));
        put( Character.valueOf( 'F' ), Byte.valueOf( (byte )15 ));
    }};
    static int[] charValues = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
                    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,10, 11, 12, 13,14,15};
    static char[] cs = new char[]{'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','A','B','C','D','E','F'};

    public static void main(String args[]) throws Exception {
        long time = System.currentTimeMillis();
        for( int i = 0; i < NUMBER_OF_RUNS; i++ ) {
            res = getNumericValue( i );
        }
        System.out.println( "Character.getNumericValue:" );
        System.out.println( System.currentTimeMillis()-time );
        time = System.currentTimeMillis();
        for( int i = 0; i < NUMBER_OF_RUNS; i++ ) {
            res = getDigit( i );
        }
        System.out.println( "Character.digit:" );
        System.out.println( System.currentTimeMillis()-time );
        time = System.currentTimeMillis();
        for( int i = 0; i < NUMBER_OF_RUNS; i++ ) {
            try {
                res = getValueFromArray( i );
            } catch (IllegalArgumentException e) {
            }
        }
        System.out.println( "Array:" );
        System.out.println( System.currentTimeMillis()-time );
        time = System.currentTimeMillis();
        for( int i = 0; i < NUMBER_OF_RUNS; i++ ) {
            res = getValueFromHashMap( i );
        }
        System.out.println( "HashMap<Character,Byte>:" );
        System.out.println( System.currentTimeMillis()-time );
        time = System.currentTimeMillis();
        for( int i = 0; i < NUMBER_OF_RUNS; i++ ) {
            char c = cs[i%cs.length];
            res = getValueFromComputeMethod( c );        
        }
        System.out.println( "JonSkeet's Direct Method:" );
        System.out.println( System.currentTimeMillis()-time );
        time = System.currentTimeMillis();
        for( int i = 0; i < NUMBER_OF_RUNS; i++ ) {
            res = getValueFromSwitch( i );

        }
        System.out.println( "Switch:" );
        System.out.println( System.currentTimeMillis()-time );
    }

    private static byte getValueFromSwitch( int i ) {
        byte res;
        char ch = cs[i%cs.length];
        switch( ch ) {
            case '0':
                res = 0;
                break;
            case '1':
                res = 1;
                break;
            case '2':
                res = 2;
                break;
            case '3':
                res = 3;
                break;
            case '4':
                res = 4;
                break;
            case '5':
                res = 5;
                break;
            case '6':
                res = 6;
                break;
            case '7':
                res = 7;
                break;
            case '8':
                res = 8;
                break;
            case '9':
                res = 9;
                break;
            case 'a':
            case 'A':
                res = 10;
                break;
            case 'b':
            case 'B':    
                res = 11;
                break;
            case 'c':
            case 'C':    
                res = 12;
                break;
            case 'd':
            case 'D':    
                res = 13;
                break;
            case 'e':
            case 'E':    
                res = 14;
                break;
            case 'f':
            case 'F':    
                res = 15;
                break;
            default:
                throw new RuntimeException("unknown hex character: " + ch );
        }
        return res;
    }

    private static byte getValueFromComputeMethod( char c ) {
        byte result = 0;
        if (c >= '0' && c <= '9')
        {
            result =  (byte)(c - '0');
        }
        if (c >= 'a' && c <= 'f')
        {
            result = (byte)(c - 'a' + 10);
        }
        if (c >= 'A' && c <= 'F')
        {
            result =  (byte)(c - 'A' + 10);
        }
        return result;
    }

    private static byte getValueFromHashMap( int i ) {
        return map.get( Character.valueOf( cs[i%cs.length] ) ).byteValue();
    }

    private static byte getValueFromArray( int i ) {
        char c = cs[i%cs.length];
        if (c < '0' || c > 'f') {
            throw new IllegalArgumentException();
        }
        byte result = (byte)charValues[c-'0'];
        if (res < 0) {
            throw new IllegalArgumentException();
        }
        return result;
    }

    private static byte getDigit( int i ) {
        return (byte)Character.digit( cs[i%cs.length], 16 );
    }

    private static byte getNumericValue( int i ) {
        return (byte)Character.getNumericValue( cs[i%cs.length] );
    }

}

解决方案

A preinitialised array would be faster than a HashMap. Something like this:

int CharValues['f'-'0'+1] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, ... -1, 10, 11, 12, ...};

if (c < '0' || c > 'f') {
    throw new IllegalArgumentException();
}
int n = CharValues[c-'0'];
if (n < 0) {
    throw new IllegalArgumentException();
}
// n contains the digit value

You should benchmark this method against other methods (such as Jon Skeet's direct method) to determine which will be the fastest for your application.

 
精彩推荐
图片推荐