如何在给定种子的范围内得到一个稳定的随机数



假设我有:

  • 种子–整数,例如1200303
  • 目标值的范围[1,20]

有没有数学方法可以得到由种子决定的[1, 20]范围内的随机数?

rand(seed int, range [int, int]);
rand(1, [1, 20]); // "4"
rand(1, [1, 20]); // "4" (if seed and range is the same, I expect the same value)
rand(1, [1, 21]); // "6" (changing range changes random number)
rand(2, [1, 20]); // "9" (changing seed changes random number)

事实证明,我一直在寻找所谓的伪随机数生成器(PRNG(。

有许多PRNG实现。Mersenne Twister是最受欢迎的,但其安全性也相当弱。

我和https://www.npmjs.com/package/seeded-rand

const SEED = 123,
const LOWER_RANGE = 1;
const UPPER_RANGE = 100;
const srand = new Srand(SEED_ID);
const gifId = srand.intInRange(LOWER_RANGE, UPPER_RANGE);

这将提供一个介于1和100之间的数字,该数字是确定的,即,在给定相同种子的情况下,多个程序执行将返回相同的数字。


更新

原来我最初的尝试并不像我想象的那样随机

https://github.com/DomenicoDeFelice/jsrand/issues/3

解决方案是首先对种子进行散列,例如

import {
createHash,
} from 'crypto';
import Srand from 'seeded-rand';
const seed = createHash('sha1').update(String(SEED)).digest().readUInt32BE();
new Srand(seed).intInRange(1, UPPER_RANGE);

如果每个种子只需要1个确定的随机值,那么这里根本不需要随机函数。只需执行seed % UPPER_RANGE(见下文(。


许多PRNG允许您指定输出范围;如果不是,它们通常是从0(包括0(到1(不包括1(,基本上这样做就足够了:

let range = (max - min);
Math.floor(value * range) + min

如果你走这条路,一定要仔细检查所选的实现不是1,因为它偶尔会超过最大

此外,如果你对可识别的可预测性模式满意,那么你可以只使用SEED % UPPER_RANGE,即

123 % 20; // "3"
124 % 20; // "4"
// ...
164 % 20; // "4"

感谢Freenode的joepie91的指导。我只是在记录他的建议。

我写了一个关于如何使用简单数学和循环来实现这一点的概念。我相信细节可以改进,但总的来说,你想要这样的东西吗?

// Seed random (pseudo-random)
const seedRand = (num, range) => {
// Generate number multiplication
num = String(num).split('').reduce((c, n) => (n != 0) ? c * n : c * c);
// Transform to match range
let s = range[0],
e = range[1]
while(num < range[0] || num > range[1]) {
if(num > range[1]) num = Math.floor(num / e--);
if(num < range[0]) num = Math.floor(num * s++);
}
// Return value
return num;
}
// Test
console.log(seedRand(1220501, [1, 20]));
console.log(seedRand(1520502, [1, 20]));
console.log(seedRand(1520502, [1, 20])); // Same seed as previous one
console.log(seedRand(1370503, [1, 20]));
console.log(seedRand(1370503, [1, 21])); // Same seed as previous one, different range

最新更新