為了從 int 中解壓縮第一個和第二個 4 位塊,我使用這種方法:
int chunks = 0b1111_1110_1101_1100_1011_1010_1001_1000;
int mask = 0x0f << (Integer.SIZE - 4);
byte result = (byte) ((chunks & mask) >>> (Integer.SIZE - 4));
Integer.toBinaryString(result); //print "1111"
int chunks = 0b1111_1110_1101_1100_1011_1010_1001_1000;
int mask = 0x0f << (Integer.SIZE - 8);
byte result = (byte) ((chunks & mask) >>> (Integer.SIZE - 8));
Integer.toBinaryString(result); //print "1110"
當 int 塊數位的表示從 1 位開始時,它的效果很好。
當我有這樣的數字從 0000 開始時:
int chunks = 0b0000_0110_1101_1100_1011_1010_1001_1000;
int mask = 0x0f << (Integer.SIZE - 4);
byte result = (byte) ((chunks & mask) >>> (Integer.SIZE - 4));
Integer.toBinaryString(result); //print "0"
int chunks = 0b0000_0110_1101_1100_1011_1010_1001_1000;
int mask = 0x0f << (Integer.SIZE - 8);
byte result = (byte) ((chunks & mask) >>> (Integer.SIZE - 8));
Integer.toBinaryString(result); //print "110"
它也很好用。
從性能的角度來看,這是一種最佳方法嗎?我覺得我把它復雜化了。
uj5u.com熱心網友回復:
這些操作非常瑣碎,不太可能對性能產生影響。
但如果你想深入了解它
算術運算和區域變數在使用、、或
int時無論如何都在使用。因此,除非您將值實際存盤到型別的堆變數中,否則將區域變數宣告為 沒有任何好處。相關的型別轉換意味著最低 8 位到 32 位的符號擴展操作,除非 JVM 的優化器設法消除它。byteshortcharintbytebyte除了最高有效位之外,沒有其他位。因此,當您將最高有效位移動到最低位置時,無需屏蔽它們。
對于第二個“4 位塊”,您仍然需要一個掩碼,但您不需要將其移到高位。相反,您可以先將您的位向下移動,然后使用
0xf. 由于掩碼在任何一種情況下都是常量,因此對性能沒有影響,至少在 JIT 編譯器完成作業時,位元組碼會更小。
所以,當我們使用
public static void main(String[] args) {
int[] allChunks = {
0b1111_1110_1101_1100_1011_1010_1001_1000,
0b0000_0110_1101_1100_1011_1010_1001_1000
};
for(int chunks: allChunks) {
if(firstFourBitChunkOld(chunks) != firstFourBitChunk(chunks))
throw new AssertionError();
if(secondFourBitChunkOld(chunks) != secondFourBitChunk(chunks))
throw new AssertionError();
System.out.println(Integer.toBinaryString(firstFourBitChunk(chunks)));
System.out.println(Integer.toBinaryString(secondFourBitChunk(chunks)));
System.out.println();
}
}
static int firstFourBitChunk(int chunks) {
return chunks >>> 28;
}
static int secondFourBitChunk(int chunks) {
return chunks >>> 24 & 0xf;
}
private static final int MASK_FIRST_FOUR_BITS = 0x0f << (Integer.SIZE - 4);
static byte firstFourBitChunkOld(int chunks) {
return (byte) ((chunks & MASK_FIRST_FOUR_BITS) >>> (Integer.SIZE - 4));
}
private static final int MASK_SECOND_FOUR_BITS = 0x0f << (Integer.SIZE - 8);
static byte secondFourBitChunkOld(int chunks) {
return (byte) ((chunks & MASK_SECOND_FOUR_BITS) >>> (Integer.SIZE - 8));
}
eg 是否Integer.SIZE - 4比28. 我必須查一下它是Integer.SIZE指“以位為單位的大小”還是“以位元組為單位的大小”或完全不同的東西。名字不說。int我認為,一般來說,開發人員在執行位操作之前應該知道 Java有 32 位。但是由于運算式Integer.SIZE - 4是一個常量,所以這個選擇對編譯后的代碼完全沒有影響。
上面的代碼將成功運行,我們還可以比較生成的位元組碼:
static int firstFourBitChunk(int);
0: iload_0
1: bipush 28
3: iushr
4: ireturn
static int secondFourBitChunk(int);
0: iload_0
1: bipush 24
3: iushr
4: bipush 15
6: iand
7: ireturn
static byte firstFourBitChunkOld(int);
0: iload_0
1: ldc #8 // int -268435456
3: iand
4: bipush 28
6: iushr
7: i2b
8: ireturn
static byte secondFourBitChunkOld(int);
0: iload_0
1: ldc #10 // int 251658240
3: iand
4: bipush 24
6: iushr
7: i2b
8: ireturn
是i2b附加符號擴展操作。為了加載移位掩碼,ldc需要一條指令,該指令從常量池中加載一個值。在這種情況下,常量本身將占用常量池中的另外五個位元組。除此之外,代碼是等效的。
如前所述,它可能對正常的優化執行環境中的實際性能沒有實際影響。但是,我認為較短的變體也更具可讀性,至少對于對位運算有必要了解的開發人員而言。無論如何,如果沒有這種理解,就無法讓觀眾閱讀它。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/497593.html
