简体   繁体   English

用Java最快,最高效地将字节数组转换为29位整数

[英]Fastest and most efficient conversion of a byte array to a 29 bit integer in Java

Since 29 bit integers are popular in AMF, I would like to incorporate the fastest / best routine known. 由于AMF中普遍使用29位整数,因此我想结合已知的最快/最佳例程。 Two routines currently exist in our library and can be tested live on ideone http://ideone.com/KNmYT 我们的库中当前存在两个例程,可以在ideone上对其进行实时测试http://ideone.com/KNmYT
Here is the source for quick reference 这是快速参考的来源


public static int readMediumInt(ByteBuffer in) {
    ByteBuffer buf = ByteBuffer.allocate(4);
    buf.put((byte) 0x00);
    buf.put(in.get());
    buf.put(in.get());
    buf.put(in.get());
    buf.flip();
    return buf.getInt();
}

public static int readMediumInt2(ByteBuffer in) { byte[] bytes = new byte[3]; in.get(bytes); int val = 0; val += bytes[0] * 256 * 256; val += bytes[1] * 256; val += bytes[2]; if (val < 0) { val += 256; } return val; }

Usually I'd do this with bit operations. 通常我会用位操作来做到这一点。 The second version might eventually get optimized to something close to this by the JVM, but one can't be sure. 第二个版本最终可能会被JVM优化为接近此版本的版本,但是不能确定。 Now, this is only 24 bits, following your samples, but the question says "29 bit integer". 现在,跟随您的样本,它只有24位,但问题是“ 29位整数”。 I'm not sure which you really wanted. 我不确定您真正想要哪个。

public static int readMediumInt(ByteBuffer buf) {
  return ((buf.get() & 0xFF) << 16) 
       | ((buf.get() & 0xFF) <<  8)
       | ((buf.get() & 0xFF);
}

If you do actually want to read AMF 29-bit integers, this should do the job (assuming i've understood the format correctly): 如果您确实想读取AMF 29位整数,则应该可以完成此工作(假设我正确理解了格式):

private static int readMediumInt(ByteBuffer buf) {
    int b0, b1, b2;
    if ((b0 = buf.get()) >= 0) return b0;
    if ((b1 = buf.get()) >= 0) return ((b0 << 7) & ((~(-1 << 7)) << 7)) | b1;
    if ((b2 = buf.get()) >= 0) return ((b0 << 14) & ((~(-1 << 7)) << 14)) | ((b1 << 7) & ((~(-1 << 7)) << 7)) | b2;
    return ((b0 << 22) & ((~(-1 << 7)) << 22)) | ((b1 << 15) & ((~(-1 << 7)) << 15)) | ((b2 << 8) & ((~(-1 << 7)) << 8)) | (buf.get() & 0xff);
}

The most important change is to avoid allocating objects within the method. 最重要的更改是避免在方法内分配对象。 By the way your micro benchmark didn't reset "start", so the second result includes the time used for the first method. 顺便说一下,您的微基准测试没有重置“开始”,因此第二个结果包括第一种方法所用的时间。 Also, you need to run micro benchmarks multiple times, otherwise the just in time compiler has no chance to run. 另外,您需要多次运行微基准测试,否则即时编译器将无法运行。 I suggest to use a method similar to 我建议使用类似的方法

public static int readMediumInt3(ByteBuffer buf) {
    return ((buf.get() & 0xff) << 16) + 
            ((buf.get() & 0xff) << 8) + 
            ((buf.get() & 0xff));
}

The complete code is: 完整的代码是:

import java.nio.ByteBuffer;

public class Main {

    public static int readMediumInt(ByteBuffer in) {
        ByteBuffer buf = ByteBuffer.allocate(4);
        buf.put((byte) 0x00);
        buf.put(in.get());
        buf.put(in.get());
        buf.put(in.get());
        buf.flip();
        return buf.getInt();
    }

    public static int readMediumInt2(ByteBuffer in) {
        byte[] bytes = new byte[3];
        in.get(bytes);
        int val = 0;
        val += bytes[0] * 256 * 256;
        val += bytes[1] * 256;
        val += bytes[2];
        if (val < 0) {
            val += 256;
        }
        return val;
    }

    public static int readMediumInt3(ByteBuffer buf) {
        return ((buf.get() & 0xff) << 16) + 
                ((buf.get() & 0xff) << 8) + 
                ((buf.get() & 0xff));
    }

    public static void main(String[] args) {
        Main m = new Main();
        for (int i = 0; i < 5; i++) {
            // version 1
            ByteBuffer buf = ByteBuffer.allocate(4);
            buf.putInt(424242);
            buf.flip();
            long start;
            start = System.nanoTime();
            for (int j = 0; j < 10000000; j++) {
                buf.position(0);
                readMediumInt(buf);
            }
            start = System.nanoTime() - start;
            System.out.printf("Ver 1: elapsed: %d ms\n", start / 1000000);

            // version 2
            ByteBuffer buf2 = ByteBuffer.allocate(4);
            buf2.putInt(424242);
            buf2.flip();
            start = System.nanoTime();
            for (int j = 0; j < 10000000; j++) {
                buf2.position(0);
                readMediumInt2(buf2);
            }
            start = System.nanoTime() - start;
            System.out.printf("Ver 2: elapsed: %d ms\n", start / 1000000);

            // version 3
            ByteBuffer buf3 = ByteBuffer.allocate(4);
            buf3.putInt(424242);
            buf3.flip();
            start = System.nanoTime();
            for (int j = 0; j < 10000000; j++) {
                buf3.position(0);
                readMediumInt3(buf3);
            }
            start = System.nanoTime() - start;
            System.out.printf("Ver 3: elapsed: %d ms\n", start / 1000000);
        }

    }
}

My results: 我的结果:

  • Ver 1: elapsed: 556 ms 版本1:经过时间:556毫秒
  • Ver 2: elapsed: 187 ms Ver 2:经过的时间:187毫秒
  • Ver 3: elapsed: 3 ms 版本3:经过时间:3毫秒

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM