Javascript 无法正确计算 xorshiftmult。如何让它发挥作用?

Javascript fails to calculate xorshiftmult correctly. How to make it work?

我正在尝试做与静态类型语言相同的数学运算,但如果参数很大,它会给我不同的数字。

function xorshiftmult(x) {
    x ^= x >> 12n
    x ^= x << 25n
    x ^= x >> 27n
    return BigInt.asUintN(64, x * 2685821657736338717n)
}

小数:

input/output

1n 5180492295206395165n
2n 10360984590412790330n
3n 15541476885619185495n
4n 4961046764852367761n
5n 4769895744586085492n
6n 15322031355265158091n
7n 15130880334998875822n
8n 9922093529704735522n
9n 15102585824911130687n

大数:

input/output

7292821753470094447n 4831377277631613306n
17517393223776413492n 8648459866934146562n
12871125787594255668n 10283147200615164616n
16549285201548370653n 6000770026373893856n
18260228909704403279n 13976674343699112182n
7574594482456054693n 16722430591553842838n
17620850200451425087n 15710702043522419077n
11252008783195621033n 12240320011096546170n
13791874522026752862n 7426906761295174006n
12869035004249813321n 1654853426672194495n

(戈兰语)

func xorshiftmult(x uint64) uint64 {
    x ^= x >> 12
    x ^= x << 25
    x ^= x >> 27
    return x * 2685821657736338717
}

小数:

input/output

1 5180492295206395165
2 10360984590412790330
3 15541476885619185495
4 4961046764852367761
5 4769895744586085492
6 15322031355265158091
7 15130880334998875822
8 9922093529704735522
9 15102585824911130687

大数字:

input/output

7292821753470094447 4375439080089995642
17517393223776413492 3385204219959375362
12871125787594255668 13047519269082376904
16549285201548370653 13622873389358370528
18260228909704403279 10325503129038119158
7574594482456054693 7461249648354733718
17620850200451425087 13330604890916407685
11252008783195621033 8666328877708335994
13791874522026752862 16881109032334662006
12869035004249813321 14233246107464520639

如你所见,大数字是不同的。但为什么?我做错了什么?

你需要在每一步都限制数字,而不仅仅是在最后。否则,您向左移动超过第 64 位的位稍后会在您再次向右移动时返回,而在 Go 中它们已经“掉下悬崖”了。

例如,如果您的输入是 2^50,则第一步将得到 2^50+2^38,然后第二步将得到 2^50+2^38+2^75+2^63(而在 Go 中,此时你只会得到 2^50+2^38+2^63),所以在第三步之后你会得到 2^50+2^38+2^75+2^63+2^23+2^11+2^48+2^36(在围棋中 2^75并且 2^48 不存在)并且在钳位之后最终结果是 2^50+2^38+2^63+2^23+2^11+2^48+ 2^36 - 在 Go 中,2^48 不会存在,因为它来自第二步中的 2^75,在 Go 中,它已经被钳制,并且不能在下一步中引入 2^48 .

function xorshiftmult(x) {
    x = BigInt.asUintN(64, x ^ x >> 12n)
    x = BigInt.asUintN(64, x ^ x << 25n) 
    x = BigInt.asUintN(64, x ^ x >> 27n)
    return x
} 

注意:从技术上讲,只在<<步使用BigInt.asUintN就足够了,因为>>步不能产生更大的 个数字,只有更小的数字。无论如何我都会这样做,为了保持一致性,但如果速度是问题,可以改用它:

function xorshiftmult(x) {
    x ^= x >> 12n
    x = BigInt.asUintN(64, x ^ x << 25n) 
    x ^= x >> 27n
    return x
}