【问题标题】:What is the most efficient way in Java to sign extend an arbitrary length pattern of bits?在 Java 中签名扩展任意长度的位模式的最有效方法是什么?
【发布时间】:2019-02-13 16:43:23
【问题描述】:

假设,例如,我将三个 10 位有符号整数打包成一个 Java 整数。

我可以轻松提取这 10 位:

int unpacked = packed & 0x3FF;
packed >>= 10;
etc ...

但现在我需要对最高位(右起第 9 位)进行符号扩展。有没有一种快速的方法来测试最高位和设置?

也许有一种更好的拆包方法可以让标志留在原处。

【问题讨论】:

  • 高 32-10 位有两个可能的值 - 全为 1 或全为 0。所以你可以在一个(有条件的)步骤中做到这一点。
  • 是的 - 我会纠正我的问题,但我可以在没有 if 语句的情况下这样做吗?
  • 也许我遗漏了一些东西,但 0x2ff 的结果应该是什么? (0b10 1111 1111)?根据接受的答案是十进制的 -255 还是 -1052672?
  • 我正在查询,但我认为如果你得到正确的数字,向上然后向下移动将起作用。
  • @rghome 将 0x2ff 向上移动然后向下移动会给你 -257 (0b1111 1111 1111 1111 1111 1110 1111 1111)

标签: java bit-manipulation sign-extension


【解决方案1】:

移动两次的替代方法是翻转符号然后减去它:

int unpacked = packed & 0x3FF;
int extended = (unpacked ^ 0x200) - 0x200;

如果符号没有设置,翻转它会设置它并减去它会再次重置它。

如果设置了符号,翻转它会重置它,减去它会再次设置它,但也会一直借到顶部,一路设置所有位。

这有一些好处,

  • 代码不依赖于目标整数类型的大小,如果unpackedextendedlong,那么同样的事情会起作用。
  • XOR 和减法可能会便宜一些,例如在 Skylake 上,您每个周期可以执行 4 次这些基本操作,但只有 2 班。延迟是一样的,只有当代码中可用的 ILP 很高时才有意义。
  • 移位并不能真正以代数方式组合,但 XOR 和减法可以。例如,如果下一个操作是向extended 添加一些常量,则可以将加法和“减号”步骤合并为一个操作。

【讨论】:

    【解决方案2】:
    int signed = (packed << (32 - 10)) >> (32 - 10);
    

    &gt;&gt;&gt; 是无符号右移,&gt;&gt; 是有符号右移。

    (我仍然有“错误”,感谢@rghome)

    【讨论】:

    • 是的,&gt;&gt; 是一个算术移位,所以它会对值进行符号扩展
    • 我的意思是,金额。向上移动 22 和向下移动 10 是 12 的净移动,这是不想要的。
    • @rghome 我忽略了那个非常明显的错误,比如* (32 - 10) / 10。感谢您的澄清。
    猜你喜欢
    • 1970-01-01
    • 2011-12-09
    • 1970-01-01
    • 1970-01-01
    • 2014-09-27
    • 2021-11-28
    • 2011-02-18
    • 1970-01-01
    • 2010-10-10
    相关资源
    最近更新 更多