1

我想知道我的整数字节的大小。例子 :

public static void main(String[] args) throws IOException {
   int a = 256;
   System.out.println(nbBytes(a));
}

static byte nbBytes(int value) {
   byte l = 0;
   while (value != 0) {
      value >>>= 8;
      ++l;
   }
   return l;
}

它工作得很好,但我想优化这个计算。你有提议吗?:D

4

3 回答 3

2

如果您指的是运行时性能,那么以下算法(最初找到最高设置位)可能是最快的。我已经修改它以返回编码整数参数所需的字节数:

private static final int[] DE_BRUIJN_BIT_POSITION_LUT = {
      0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
      8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
    };

public static int nbBytes2(int n) {
    n |= n >> 1;  
    n |= n >> 2;
    n |= n >> 4;
    n |= n >> 8;
    n |= n >> 16;
    return DE_BRUIJN_BIT_POSITION_LUT[((n * 0x07C4ACDD) >> 27) & 0x1f] / 8 + 1;
}

即使它看起来更复杂,它也没有任何循环或条件处理,从而可以优化使用现代 CPU 管道。

将 De Bruijn 算法与您的方法进行比较,您的方法对于 0x0-0xff 范围内的输入要快约 4 倍(您的方法也不会分支)。对于 0x100-0xfff 范围内的输入,我的方法快 19 倍,输入 0x10000-0xffffff 快 28 倍,输入 >0x1000000 快 35 倍。所有数字都对我的硬件有效,在其他计算机上它当然可能不同。

于 2012-10-29T16:21:31.400 回答
1

在 Java 中,anint始终是 32 位有符号的 2 补码值。例如,参见Java 虚拟机规范的第 2.3 节

如果您想知道存储特定值的最小位数,可以使用Integer.numberOfLeadingZeros以下方法获得:

int bitsNeeded = 32 - Integer.numberOfLeadingZeros(value);

然后,您可以四舍五入以获得所需的字节数。

如果您运行的是不包含此功能的旧版 Java,这里是它的 1.6 源代码:

public static int numberOfLeadingZeros(int i) {
    if (i == 0)
        return 32;
    int n = 1;
    if (i >>> 16 == 0) { n += 16; i <<= 16; }
    if (i >>> 24 == 0) { n +=  8; i <<=  8; }
    if (i >>> 28 == 0) { n +=  4; i <<=  4; }
    if (i >>> 30 == 0) { n +=  2; i <<=  2; }
    n -= i >>> 31;
    return n;
}

我认为,这是否比你已经在做的更有效只能通过分析来确定。它还取决于您期望遇到的值的分布。

如果您只希望处理非负值,我会这样做:

static byte nBytes(int value) {
    if (value < (1 << 8)) return 1;
    if (value < (1 << 16)) return 2;
    if (value < (1 << 24)) return 3;
    return 4;
}

这假设您需要 1 个字节来表示零。要处理负数,有两种逻辑选择:

  1. 总是返回 4
  2. 返回表示 2 的补码中的值所需的最小字节数。

对于第二种情况,我会执行以下操作:

static byte nBytes(int value) {
    if (value < 0) {
        if (value > Integer.MIN_VALUE) {
            value = -value;
            if (value < (1 << 7)) return 1;
            if (value < (1 << 15)) return 2;
            if (value < (1 << 23)) return 3;
        }
    } else {
        if (value < (1 << 8)) return 1;
        if (value < (1 << 16)) return 2;
        if (value < (1 << 24)) return 3;
    }
    return 4;
}
于 2012-10-29T16:01:53.633 回答
0

我不知道这是更优化的,但另一种解决方案类似于(未测试):

return (byte)Math.ceil(Integer.toBinaryString(value).length()/8.0);
于 2012-10-29T16:07:02.390 回答