我想知道我的整数字节的大小。示例:
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
答案 0 :(得分: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倍。所有数字对我的硬件都有效,在其他计算机上它当然可能不同。
答案 1 :(得分:1)
在Java中,int
始终是32位,带符号的二进制补码值。例如,请参阅Section 2.3 of the Java Virtual Machine Specification。
如果您想知道存储特定值的最小位数,可以使用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个字节来表示零。要处理负数,有两个合理的选择:
对于第二种情况,我会做以下事情:
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;
}
答案 2 :(得分:0)
我不知道这是更优化,但另一种解决方案是(未经测试):
return (byte)Math.ceil(Integer.toBinaryString(value).length()/8.0);