JavaScript计算xorshiftmult大数值结果异常,如何正确实现?
差异产生原因
Go的uint64是固定64位的无符号整数类型,所有位运算、算术运算执行后都会自动对结果做模2^64截断,超出64位的高位会直接丢弃。而JavaScript的BigInt是任意精度整数,默认不会做任何长度截断,运算结果会完整保留所有高位信息。
小数值输入时x的高位全为0,运算过程中不会产生有效高位,所以是否截断结果都一致;大数值输入时运算会产生高位有效位,你的代码未处理中间步骤的截断,这些额外高位会参与后续运算,最终结果就和Go版本出现偏差。
现有代码的问题
你只在最终返回时做了64位无符号截断,中间三次移位异或操作的结果都没有做截断,尤其是左移25位的操作会直接把原本64位的数值拓展到89位,多出来的高位参与后续异或、移位操作,运算逻辑已经和Go的uint64版本不一致。
修正方案
每一次位运算操作后都用BigInt.asUintN(64)对结果做截断,保证每一步x的取值都严格对应Go的uint64范围,修正后代码如下:
function xorshiftmult(x) { // 先确保入参符合uint64范围,和Go入参逻辑对齐 x = BigInt.asUintN(64, x) x = BigInt.asUintN(64, x ^ (x >> 12n)) x = BigInt.asUintN(64, x ^ (x << 25n)) x = BigInt.asUintN(64, x ^ (x >> 27n)) return BigInt.asUintN(64, x * 2685821657736338717n) }
修正后所有测试用例的输出都会和Go版本完全对齐。
内容的提问来源于stack exchange,提问作者rodaba
相关产品推荐
相关产品推荐

