首页 > 解决方案 > 如何让这个 PRNG 生成范围内的数字?

问题描述

我在下面找到了这个,用于 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))

然而,虽然fetch8andfetch16函数在重复之前正确地循环遍历整个数字集,但build8andbuild16函数却没有,它们超出了所需的范围,请参见上述代码的输出。例如,当i = 11j = 184x = 340,即> 255

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

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

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

标签: javascriptmathrandomcryptography

解决方案


您超出范围值的原因是,虽然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);


推荐阅读