为什么我的 Go 实现的 xorshift128+ 没有产生与 JavaScript 相同的结果?

问题描述 投票:0回答:1

我正在尝试实现一个 PNRG (xorshift128+),它将在客户端 (Go) 和服务器 (Node) 上生成时进行匹配。

这是JS代码:

function xor128(aT, Gj) {
     var SM = aT;
     var tn = Gj;
     return function() {
         var Fv = SM;
         Fv ^= Fv << 23;
         Fv ^= Fv >> 17;
         var RW = tn;
         Fv ^= RW;
         SM = RW;
         Fv ^= RW >> 26;
         tn = Fv;
         return (SM + tn) % 4294967296;
     };
 }

buildKeyArray(section, max, seed) {
    const randomNumberGenerator = xor128(section, seed);
    const outputArray = [];

    for (let index = 0; index < max; index++) {
        const a = randomNumberGenerator()
        outputArray.push(a & 255);
    }

    return outputArray;
}

这是我尝试实现的客户端(Go)代码:

type Xor128Generator struct {
    SM uint32
    tn uint32
}

func NewXor128Generator(aT, Gj uint32) *Xor128Generator {
    return &Xor128Generator{SM: aT, tn: Gj}
}

func (x *Xor128Generator) Generate() uint32 {
    Fv := x.SM
    Fv ^= Fv << 23
    Fv &= 0xFFFFFFFF // 32-bit wrap around
    Fv ^= Fv >> 17
    Fv &= 0xFFFFFFFF // 32-bit wrap around
    RW := x.tn
    Fv ^= RW
    Fv &= 0xFFFFFFFF // 32-bit wrap around
    x.SM = RW
    Fv ^= RW >> 26
    Fv &= 0xFFFFFFFF // 32-bit wrap around
    x.tn = Fv

    result := uint32(x.SM) + uint32(x.tn)
    return uint32(result)
}

func (x *XorEncoder) buildKeyArray() []byte {
    gen := NewXor128Generator(x.XorSection, x.Xor128Seed)
    outputArray := make([]byte, x.Xor128Max)

    for index := 0; index < x.Xor128Max; index++ {
        var a = gen.Generate()
        outputArray[index] = byte(a & 255)
    }

    return outputArray
}

问题是我的 Go 实现从 xor128 代码生成不同的数字。我理解这是因为 Node 使用 32 位整数,而 Go 使用 64 位整数。但是如何修复 Go 代码,使其与 JS 代码保持一致,并在两个平台上生成相同的数字。

需要明确的是,JS 代码正在生成正确的值,并且 Go 代码需要匹配。

go
1个回答
0
投票

您没有提供任何示例值,代码可能存在多个问题,但我会指出我发现的第一个问题。

考虑 javascript:

Fv ^= Fv << 23;
Fv ^= Fv >> 17;

如果

Fv << 23
的结果导致高位被设置,则
Fv >> 17
传播符号;在代码中可能更容易看到这一点(
>>>
是一个无符号右移):

function dec2bin(dec) {
  return (dec >>> 0).toString(2);
}

let Fv = 0b11000000000000000000000000000000
console.log(Fv >> 23, dec2bin(Fv >> 23));
console.log(Fv >>> 23, dec2bin(Fv >>> 23));

输出为:

-128  11111111111111111111111110000000
384   110000000

当您现在使用

^=
中的结果时,您可以看到符号传播将如何产生影响。

在你的 Go 代码中,你自始至终都在使用

uint32
;由于这是无符号的,移位运算不会传播符号,这将导致差异。让我们比较一下有符号整数和无符号整数的使用:

package main

import "fmt"

type Xor128Generator[T interface{ int32 | uint32 }] struct {
    SM T
    tn T
}

func (x *Xor128Generator[T]) Generate() T {
    Fv := x.SM
    Fv ^= Fv << 23
    Fv ^= Fv >> 17
    RW := x.tn
    Fv ^= RW
    x.SM = RW
    Fv ^= RW >> 26
    x.tn = Fv

    return x.SM + x.tn
}

func main() {
    u := Xor128Generator[uint32]{SM: 65535, tn: 1}
    fmt.Println(u.Generate()) // output: 4286611519

    i := Xor128Generator[int32]{SM: 65535, tn: 1}
    fmt.Println(i.Generate()) // output: 8323135
}

第二个结果 (

int32
) 与您的 Javascript 输出相匹配(我运行了
 console.log(xor128(65535,1)());
)。

© www.soinside.com 2019 - 2024. All rights reserved.