首页 > 解决方案 > x & 0xffffffff 如何产生超过 32 位?

问题描述

简短的总结

我希望n & 0xffffffff产生一个 32 位的数字,而不是更多。但它产生了一个 64 位的数字。为什么?

细节

在 Android (Java) 应用程序中,我有以下代码行:

hash = ((hash ^ b) * FNV_PRIME) & 0xffffffff;

在这一步之后记录 的值时hash,我会得到 、 等值0x811d68ec0c35c40x342d586144387f57这些值显然超过 32 位可以容纳。它们是 64 位数字。

hash是类型long。我可以提供更多关于band的细节FNV_PRIME,但这似乎与问题无关。无论 的值((hash ^ b) * FNV_PRIME)是什么,当我们将它与0xFFFFFFFF32 位数字按位与时,我们应该以除最低有效 32 位之外的所有零结束。对?

int与中间结果的数据类型相比,这里是否存在隐含long的情况,并且可能使用高位表示负数?

标签: javabitwise-and

解决方案


好的,我似乎找到了解决方案。我会猜测它为什么会起作用。如果有人能对此有所了解,我会很高兴听到它。

修复:L在右侧的十六进制文字中添加一个以将其&标记为long

hash = ((hash ^ b) * FNV_PRIME) & 0xffffffffL;

我对此进行了测试,它起作用了:代码现在只产生 32 位值。

那么出了什么问题,为什么要解决它?

的左侧&是一个long值,因为hash是一个long(FNV_PRIME 也是如此,但这无关紧要)。为了&完成它的工作,它需要它的操作数是相同的类型。因此它会自动将右侧值0xffffffff, 从int提升到long。由于 Java 类型是有符号的,0xffffffff因此被解释为 -1,这long将是0xffffffffffffffff. 所以上面的行最终做了相当于

hash = ((hash ^ b) * FNV_PRIME) & 0xffffffffffffffff;

这就是我最终从中获得 64 位值的方式。

当我改为制作正确的操作数0xffffffffL时,它已经是 along并且不需要提升,因此它不会因为高位而被解释为负数。换句话说,0xffffffffL相当于0x00000000ffffffffL,所以没有设置高位。

这个故事的寓意是什么?

好吧,我可以使用帮助。一些想法:

  • 彻底了解 Java 如何在每次计算的每个中间阶段决定使用什么数据类型来表示数字。呃,这听起来很难,尤其是当大多数事情大部分时间都“工作正常”时。

  • 只是蒙混过关,直到某些东西不起作用,然后使用调试器更详细地跟踪它,直到找到问题为止。这假设如果程序失败,它仍然在开发人员手中时会失败。

  • 良好而彻底的单元测试。:-) 不确定我是否会设计一个能够检测到这个问题的测试,例如一个断言我的函数的返回值不超过 32 位长的测试。

  • 请特别注意 IDE 中的编译器警告。直到游戏后期我才注意到它,但最终我看到 Android Studio 有一个警告说:

    'hash = ((hash ^ b) * FNV_PRIME) & 0xffffffff' 可以替换为 'hash = ((hash ^ b) * FNV_PRIME)'

如果我早点读到,我会非常困惑,但它会给我一个很好的线索来解决这个问题。


推荐阅读