【问题标题】:Javascript fails to calculate xorshiftmult correctly. How to make it work?Javascript 无法正确计算 xorshiftmult。如何让它发挥作用?
【发布时间】:2021-12-15 11:52:27
【问题描述】:

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

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

(golang)

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

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

【问题讨论】:

    标签: javascript math bit-manipulation bigint


    【解决方案1】:

    您需要在每一步都限制数字,而不仅仅是在最后。否则,当您再次右移时,您向左移动超过第 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(在 Go 中不存在 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
    } 
    

    注意:从技术上讲,仅在&lt;&lt; 步骤中使用BigInt.asUintN 就足够了,因为&gt;&gt; 步骤不能产生更大的数字,只能产生更小的数字.无论如何,为了保持一致性,我还是会这样做,但如果担心速度,可以使用它来代替:

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

    【讨论】:

    • @rodaba 不客气,但该评论对于未来的读者来说不是必需的,这也不是。评论是短暂的,它们应该用于要求澄清或指出问题,并且在不再需要时可以并且将被删除。我们可能很快也会删除此对话,因为它不会为答案增加任何价值。那是因为 Stack Overflow 不是一个论坛,而是一个知识库。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多