【问题标题】:How to get this PRNG to generate numbers within the range?如何让这个 PRNG 生成范围内的数字?
【发布时间】:2021-04-27 12:14:53
【问题描述】:

我在下面找到了this,用于 JavaScript 中的 8 位和 16 位数字:

const fetch = (x, o) => {
  if (x >= o) {
    return x
  } else {
    const v = (x * x) % o
    return (x <= o / 2) ? v : o - v
  }
}

const fetch16 = (x) => fetch(x, 65519)
const fetch8 = (x) => fetch(x, 251)

// the last number can be anything.
const build16 = (x, o) => fetch16((fetch16(x) + o) ^ 42703)
const build8 = (x, o) => fetch8((fetch8(x) + o) ^ 101)

let i = 0
let invalid = []
while (i < 255) {
  let j = 0
  while (j < 255) {
    let x = build8(i, j)
    if (x > 255) {
      invalid.push([ i, j, x ])
    }
    j++
  }
  i++
}

console.log(JSON.stringify(invalid))

然而,虽然 fetch8fetch16 函数可以正确在重复之前循环遍历整个数字集,但 build8build16 函数不能,它们超出了所需的范围,请参阅上述代码的输出。比如i = 11j = 184时,x = 340就是&gt; 255

但是,build8build16 函数的输出非常棒。它看起来完全是随机的,并且在遍历整个集合之前不会重复任何值。

如何修改这些 build8build16 函数,使它们只包含集合中的数字(0-255 或 0-65535),但又像这里一样显得完全随机,但从不重复在经历所有这些之前的价值?

我不完全确定帖子的作者是如何登陆fetch8((fetch8(x) + o) ^ 101) 的,例如,执行 XOR 并传递这样的值。但最终结果显得非常随机。我只是想这样做,所以输出是:

  • 在所需的值范围内。
  • 在枚举完所有值之前不重复任何值。
  • 像 build8 一样完全随机。

【问题讨论】:

  • 我发现 buildXX 接受两个参数并且你改变它们两个参数,从而提供更多的组合可能性,如果可以产生结果,我会感到困惑。为什么这里有 2 个维度而不是 1 个维度?
  • "我不完全确定帖子的作者是如何登陆fetch8((fetch8(x) + o) ^ 101)" - 你是说that post 的作者吗?我在该页面上找不到任何类似于 build8 的代码。

标签: javascript math random cryptography


【解决方案1】:

你得到超出范围值的原因是,虽然fetchXX 会产生一个范围内的值,但+ o 破坏了这个属性。 XOR 操作可能有时会将其带回范围内,但并非总是如此。

所以你应该取+ o之后的值的模。 XOR 操作永远不会使其超出范围,因此可以保持原样。

其次,要测试是否没有生成重复项,您需要修复传递给buildXX 函数的两个参数之一,只改变另一个。冻结第二个论点对我来说似乎更合乎逻辑。

这就是它的样子:

const fetch = (x, o) => {
  if (x >= o) {
    return x
  } else {
    const v = (x * x) % o
    return (x <= o / 2) ? v : o - v
  }
}

const fetch16 = (x) => fetch(x, 65519)
const fetch8 = (x) => fetch(x, 251)

// the last number can be anything.
const build16 = (x, o) => fetch16((fetch16(x) + o) % 65536 ^ 42703)
const build8 = (x, o) => fetch8((fetch8(x) + o) % 256 ^ 101)

const j = 115; // If you don't want duplicates, either i or j should stay fixed
let i = 0
let invalid = [];
let valid = new Set;
while (i <= 255) { // <-- small fix here!
    let x = build8(i, j); // To test, you can swap i and j here, and run again.
    if (x > 255) {
        invalid.push([ i, j, x ]);
    } else {
        valid.add(x);
    }
    i++;
}

console.log("invalid:", JSON.stringify(invalid));
console.log("count of valid:", valid.size);

【讨论】:

  • 是否可以编写一个计算build8 的逆/逆的函数? stackoverflow.com/questions/68850952/…
  • 出于某种原因,将最大值从 65536 替换为不同的值 ((32 * 16) ** 3),并更改其他值会导致它产生大量重复。我不知道为什么。 gist.github.com/lancejpollard/24b6c611d4d159b39a80314709550f5e 想知道这是否仅在一切都是 2 的清洁幂时才有效。
  • 此代码中的值 65519 和 251 应该是素数,最好是低于该范围的最大素数。当您要对% 运算符的结果进行异或运算时,值 65536 确实应该是 2 的幂。
  • 我想我错过了素数也必须满足p≡3mod4的事实,去看看。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-02
  • 1970-01-01
  • 2014-02-20
  • 2010-10-02
  • 1970-01-01
相关资源
最近更新 更多