首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java int优化中的4位块解包

Java int优化中的4位块解包
EN

Stack Overflow用户
提问于 2022-06-23 05:01:02
回答 1查看 62关注 0票数 1

为了从int中解压缩第一个和第二个4位块,我使用了以下方法:

代码语言:javascript
复制
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"

当整数块数位的表示从1位开始时,它会工作得很好。

当我有这样的号码从0000开始:

代码语言:javascript
复制
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"

它也很好用。

从性能的角度来看,这是一种最好的方法吗?我觉得我把事情复杂化了。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-06-23 11:42:49

这些操作如此琐碎,不太可能对性能产生影响。

但如果你想投入其中

  1. 算术操作和局部变量在使用byteshortcharint时仍然使用int。因此,除非实际将值存储到byte类型的堆变量中,否则将局部变量声明为byte没有好处。关联类型强制转换意味着最低8位到32位的符号扩展操作,除非JVM的优化器设法消除它。

  1. 除了最重要的比特之外,没有其他的位。因此,当您将最重要的位移到最低位置时,就没有必要掩盖它们了。

对于第二个“4位块”,

  1. 仍然需要一个掩码,但不需要将其转换为高级位置。相反,您可以首先移动您的位元,然后使用0xf掩蔽它们。由于掩码在这两种情况下都是常量,所以对性能没有影响,至少当JIT编译器完成其工作时,字节码将更小。

所以,当我们用

代码语言:javascript
复制
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));
}

例如,Integer.SIZE - 428更具可读性,这一点值得商榷。我必须查找Integer.SIZE是否意味着“大小(位)”或“大小(字节)”,还是完全不同的意思。名字说不出来。我认为,一般来说,在执行位操作之前,开发人员应该知道Java的int有32位。但是,由于表达式Integer.SIZE - 4是常量,所以这种选择对编译后的代码没有任何影响。

上面的代码将成功运行,我们还可以比较生成的字节码:

代码语言:javascript
复制
  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指令,它从常量池加载一个值。在这种情况下,常量本身将在常量池中再占用五个字节。除此之外,代码是等价的。

如前所述,在正常、优化的执行环境中,它可能不会对实际性能产生实际影响。但是,我认为较短的变体也更易读,至少对于对位算术有必要理解的开发人员来说是如此。如果没有这种理解,就没有办法让观众读懂它。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72724771

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档