java - x & 0xffffffff 如何产生超过 32 位?
问题描述
简短的总结
我希望n & 0xffffffff
产生一个 32 位的数字,而不是更多。但它产生了一个 64 位的数字。为什么?
细节
在 Android (Java) 应用程序中,我有以下代码行:
hash = ((hash ^ b) * FNV_PRIME) & 0xffffffff;
在这一步之后记录 的值时hash
,我会得到 、 等值0x811d68ec0c35c4
,0x342d586144387f57
这些值显然超过 32 位可以容纳。它们是 64 位数字。
hash
是类型long
。我可以提供更多关于b
and的细节FNV_PRIME
,但这似乎与问题无关。无论 的值((hash ^ b) * FNV_PRIME)
是什么,当我们将它与0xFFFFFFFF
32 位数字按位与时,我们应该以除最低有效 32 位之外的所有零结束。对?
int
与中间结果的数据类型相比,这里是否存在隐含long
的情况,并且可能使用高位表示负数?
解决方案
好的,我似乎找到了解决方案。我会猜测它为什么会起作用。如果有人能对此有所了解,我会很高兴听到它。
修复: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)'
如果我早点读到,我会非常困惑,但它会给我一个很好的线索来解决这个问题。
推荐阅读
- kotlin - 阻止泛型在 Kotlin 中推断任何类型
- java - NoSuchFieldException:驱动程序
- kotlin - 如何降低攀登排行榜的代码复杂度?
- apache-kafka - org.apache.kafka.clients.consumer.Consumer.poll 长时间阻塞
- google-chrome - 运行 Protractor 测试时 ChromeDriver 和 Chrome 之间的版本不匹配,但没有可用的更新
- node.js - MongoDB,如何在 $lookup 解析的字段上使用 $geoNear
- javascript - 在 reactJs 中将对象添加到我的购物车中的数组
- oracle - NiFi 数据库连接池无法正常工作
- java - 如何在java中使用递归打印附加图像中显示的模式
- python - Python请求头部,只获取重定向的url,不要遵循重定向