在 JavaScript 中使用种子生成随机数
本文介绍如何使用种子从 PRNG 生成随机数。 同时,确保 PRNG 的种子具有高熵是最佳实践。
因此,我们将使用哈希函数来生成种子。 之后,我们将种子传递给 PRNG。
使用种子和 SFC32 生成随机数
SFC32 或 Simple Fast Counter 是 PractRand 的快速 PRNG(主要使用 C 语言),它在 JavaScript 中有一个 128 位状态的实现,而且速度非常快。 SFC32 至少需要一个种子来生成随机数。
我们将使用哈希函数生成这个种子,这是 MurmurHash3 的 JavaScript 实现,它需要一个初始字符串来生成种子。 结果,我们传入了一个字符串。
在下面的代码中,我们生成种子并将其传递给返回随机数的 SFC32。
代码:
// Define the Murmur3Hash function
function MurmurHash3(string) {
let i = 0;
for (i, hash = 1779033703 ^ string.length; i < string.length; i++) {
let bitwise_xor_from_character = hash ^ string.charCodeAt(i);
hash = Math.imul(bitwise_xor_from_character, 3432918353);
hash = hash << 13 | hash >>> 19;
} return () => {
// Return the hash that you can use as a seed
hash = Math.imul(hash ^ (hash >>> 16), 2246822507);
hash = Math.imul(hash ^ (hash >>> 13), 3266489909);
return (hash ^= hash >>> 16) >>> 0;
}
}
function SimpleFastCounter32(seed_1, seed_2, seed_3, seed_4) {
return () => {
seed_1 >>>= 0; seed_2 >>>= 0; seed_3 >>>= 0; seed_4 >>>= 0;
let cast32 = (seed_1 + seed_2) | 0;
seed_1 = seed_2 ^ seed_2 >>> 9;
seed_2 = seed_3 + (seed_3 << 3) | 0;
seed_3 = (seed_3 << 21 | seed_3 >>> 11);
seed_4 = seed_4 + 1 | 0;
cast32 = cast32 + seed_4 | 0;
seed_3 = seed_3 + cast32 | 0;
return (cast32 >>> 0) / 4294967296;
}
}
let generate_seed = MurmurHash3("String for the Seed Key");
let random_number = SimpleFastCounter32(generate_seed(), generate_seed());
console.log(random_number());
console.log(random_number());
输出:
0.837073584087193
0.3599331611767411
使用种子和 Mulberry32 生成随机数
Mulberry32 也是一个 PRNG,尽管代码结构比 SFC32 更简单。 与至少需要一个种子的 SFC32 相反。
我们将使用 MurmurHash3 使用字符串生成种子。 在以下示例中,我们使用 for 循环和 Mulberry32 生成五个随机数。
代码:
// Define the Murmur3Hash function
function MurmurHash3(string) {
let i = 0;
for (i, hash = 1779033703 ^ string.length; i < string.length; i++) {
let bitwise_xor_from_character = hash ^ string.charCodeAt(i);
hash = Math.imul(bitwise_xor_from_character, 3432918353);
hash = hash << 13 | hash >>> 19;
} return () => {
// Return the hash that you can use as a seed
hash = Math.imul(hash ^ (hash >>> 16), 2246822507);
hash = Math.imul(hash ^ (hash >>> 13), 3266489909);
return (hash ^= hash >>> 16) >>> 0;
}
}
function Mulberry32(string) {
return () => {
let for_bit32_mul = string += 0x6D2B79F5;
let cast32_one = for_bit32_mul ^ for_bit32_mul >>> 15;
let cast32_two = for_bit32_mul | 1;
for_bit32_mul = Math.imul(cast32_one, cast32_two);
for_bit32_mul ^= for_bit32_mul + Math.imul(for_bit32_mul ^ for_bit32_mul >>> 7, for_bit32_mul | 61);
return ((for_bit32_mul ^ for_bit32_mul >>> 14) >>> 0) / 4294967296;
}
}
let generate_seed = MurmurHash3("String for the Seed Key");
let random_number = Mulberry32(generate_seed());
for (let i = 0; i < 5; i++) {
console.log(random_number());
}
输出:
0.13532060221768916
0.8630009586922824
0.53870237339288
0.5237146227154881
0.8748106376733631
使用种子和 Xoshiro128** 生成随机数
Vagna 教授和 Blackman 开发了 Xoshiro128** 发生器。 xorshift128 是 Xorshift PRNG 的一个家族,它是最快的 PRNG。
与 SFC32 一样,Xoshiro128** 可以在生成随机数之前至少获取一个种子。 在以下代码片段中,我们使用 MurmiurHash3 创建了所需的种子。
代码:
// Define the Murmur3Hash function
function MurmurHash3(string) {
let i = 0;
for (i, hash = 1779033703 ^ string.length; i < string.length; i++) {
let bitwise_xor_from_character = hash ^ string.charCodeAt(i);
hash = Math.imul(bitwise_xor_from_character, 3432918353);
hash = hash << 13 | hash >>> 19;
} return () => {
// Return the hash that you can use as a seed
hash = Math.imul(hash ^ (hash >>> 16), 2246822507);
hash = Math.imul(hash ^ (hash >>> 13), 3266489909);
return (hash ^= hash >>> 16) >>> 0;
}
}
function Xoshiro128_twostar(seed_1, seed_2, seed_3, seed_4) {
return () => {
let t = seed_2 << 9, y = seed_1 * 5; y = (y << 7 | y >>> 25) * 9;
seed_3 ^= seed_1; seed_4 ^= seed_2;
seed_2 ^= seed_3; seed_1 ^= seed_4; seed_3 ^= t;
seed_4 = seed_4 << 11 | seed_4 >>> 21;
return (y >>> 0) / 4294967296;
}
}
let generate_seed = MurmurHash3("String for the Seed Key");
let random_number = Xoshiro128_twostar(generate_seed(), generate_seed());
console.log(random_number());
输出:
0.6150987280998379
使用种子和 JSF 生成随机数
Bob Jenkins 创建了 Jenkins Small Fast (JSF) 生成器,这是一种快速生成器。 不过,与 SFC32 相比,它并不快。
当您观察 JSF 的代码时,您会发现它与 SFC32 的相似之处。 在生成随机数之前,JSF 可以采用多个种子。
我们在下一个代码中使用种子和 JSF 生成十个随机数。
代码:
// Define the Murmur3Hash function
function MurmurHash3(string) {
let i = 0;
for (i, hash = 1779033703 ^ string.length; i < string.length; i++) {
let bitwise_xor_from_character = hash ^ string.charCodeAt(i);
hash = Math.imul(bitwise_xor_from_character, 3432918353);
hash = hash << 13 | hash >>> 19;
} return () => {
// Return the hash that you can use as a seed
hash = Math.imul(hash ^ (hash >>> 16), 2246822507);
hash = Math.imul(hash ^ (hash >>> 13), 3266489909);
return (hash ^= hash >>> 16) >>> 0;
}
}
function JenkinsSimpleFast32(seed_1, seed_2, seed_3, seed_4) {
return () => {
seed_1 |= 0; seed_2 |= 0; seed_3 |= 0; seed_4 |= 0;
let t = seed_1 - (seed_2 << 27 | seed_2 >>> 5) | 0;
seed_1 = seed_2 ^ (seed_3 << 17 | seed_3 >>> 15);
seed_2 = seed_3 + seed_4 | 0;
seed_3 = seed_4 + t | 0;
seed_4 = seed_1 + t | 0;
return (seed_4 >>> 0) / 4294967296;
}
}
let generate_seed = MurmurHash3("String for the Seed Key");
let random_number = JenkinsSimpleFast32(generate_seed(), generate_seed());
for (let i = 0; i < 10; i++) {
console.log(random_number());
}
输出:
0.513338076416403
0.4737987464759499
0.5743723993655294
0.4811882192734629
0.07753282226622105
0.11416710214689374
0.1270705321803689
0.15759771666489542
0.16906401910819113
0.6846413582097739
使用 seedrandom.js 生成随机数
seedrandom.js 是 David Bau 为种子随机数生成器 (RNG) 设计的库,可在 NPM 和 CDNJS 上使用。 对于本文,我们将使用 CDNJS。
使用 Seedrandom.js 时请记住以下几点。
-
您使用
new Math.seedrandom('seed key')
初始化 seedrandom。 - 您可以使用 Seedrandom 的 quick() 函数来生成 32 位随机数。
-
Seedrandom.js 的
int32()
函数返回一个 32 位有符号整数。 - 调用不带参数的 seedrandom 会导致创建一个自动播种的基于 ARC4 的 PRNG。 自动播种使用一些值,如累积的局部熵。
- Seedrandom 可以将一个对象作为第二个参数。 这个对象是 {entropy: true},结果是不可预测的。
- 在不使用 new 关键字的情况下调用 Math.seedrandom 会替换默认的 Math.random()。 替换为新的 Math.seedrandom()。
在这个例子中,我们从 CDNJS 导入了 seedrandom.js。 之后,我们使用它通过种子生成随机数。
代码:
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/3.0.5/seedrandom.min.js"></script>
<script>
let generate_random_number = new Math.seedrandom('Johnson');
console.log(generate_random_number());
</script>
</body>
输出:
0.08103389758898699
我们可以将种子与累积的熵混合。 您需要传递 {entropy: true}
作为 seedrandom 的第二个参数。
代码:
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/3.0.5/seedrandom.min.js"></script>
<script>
let generate_random_number = new Math.seedrandom('Antananarivo', { entropy: true });
for (let i = 0; i < 5; i++) {
console.log(generate_random_number());
}
</script>
</body>
输出:
0.8478730572111559
0.963664252064149
0.6002684820777331
0.4026776455839767
0.7579996916288508
此外,quick()
和 int32()
将返回随机的 32 位随机数。 前者将返回一个浮点数,而后者返回一个有符号整数。
代码:
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/3.0.5/seedrandom.min.js"></script>
<script>
let generate_random_number = new Math.seedrandom('DavidBau');
console.log("With quick():", generate_random_number.quick());
console.log("With int32():", generate_random_number.int32());
</script>
</body>
输出:
With quick(): 0.249648863915354
With int32(): -550219731
相关文章
JavaScript += 的效果
发布时间:2023/06/06 浏览次数:152 分类:JavaScript
-
本篇文章将介绍 JavaScript += 在以下情况下的效果。JavaScript 加上数字之间的相等 ;JavaScript 加上字符串之间相等 ;JavaScript 在数字和字符串之间加上相等
JavaScript 电话号码格式
发布时间:2023/06/06 浏览次数:181 分类:JavaScript
-
在本文中,我们将了解在 JavaScript 源代码中格式化电话号码的最佳方式,以及在我们的 JavaScript 代码中格式化数字的好处。JavaScript 中的电话号码格式 在 JavaScript 中,我们有多个选项可以有效地
JavaScript 中的图像加载事件
发布时间:2023/06/05 浏览次数:154 分类:JavaScript
-
本文将讨论如何在 JavaScript 中处理 .onload 事件。 我们将学习如何在上传图像后使用 JavaScript 创建警告框。我们还将了解如何通过创建警告框使用 JavaScript 检查图像是否已加载。JavaScript 中的 .
JavaScript 删除所有事件监听器
发布时间:2023/06/05 浏览次数:84 分类:JavaScript
-
本篇文章将介绍如何删除 JavaScript 中的所有事件侦听器。移除 JavaScript 中的所有事件监听器 EventTarget 接口的 addEventListener() 方法配置一个函数,只要指定的事件被传递到目标,就会调用该函数。
JavaScript 中事件冒泡和捕获的区别
发布时间:2023/06/05 浏览次数:54 分类:JavaScript
-
本文将讨论在 JavaScript 中使用的事件冒泡和事件捕获。 阅读本文后,您将清楚地了解 JavaScript 中的事件冒泡和捕获。
JavaScript 触发事件
发布时间:2023/06/05 浏览次数:171 分类:JavaScript
-
JavaScript 触发事件 在 JavaScript 中,原始方法 initEvent() 用于创建新事件。 最新更新添加了用于构建自定义事件的新关键字。 此外,在为 JavaScript 构建的清单中还有大量事件。
在 JavaScript 中交换数组元素
发布时间:2023/06/05 浏览次数:52 分类:JavaScript
-
在这里,我们将看到所有可使交换任务更加灵活的优选示例。 让我们进入代码库!在 JavaScript 中使用临时变量交换数组元素 在下面的示例中,我们将采用两个具有相应元素的数组。
在 JavaScript 中检查数组中的所有值是否为真
发布时间:2023/06/05 浏览次数:180 分类:JavaScript
-
在本篇文章中,我们将学习如何在 JavaScript 中检查数组中的所有值是否为真。在 JavaScript 中使用 every() 方法检查数组中的所有值是否为真
在 JavaScript 中存储字节数组
发布时间:2023/06/05 浏览次数:81 分类:JavaScript
-
本文将讨论如何在 JavaScript 中存储字节数组。JavaScript 中的 ArrayBuffer 对象 字节数组或字节数组在 JavaScript 中称为 ArrayBuffer 对象。