• 如何在 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());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    输出:

    0.837073584087193
    0.3599331611767411
    
    • 1
    • 2

    使用种子和 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());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    输出:

    0.13532060221768916
    0.8630009586922824
    0.53870237339288
    0.5237146227154881
    0.8748106376733631
    
    • 1
    • 2
    • 3
    • 4
    • 5

    使用种子和 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());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    输出:

    0.6150987280998379
    
    • 1

    使用种子和 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());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    输出:

    0.513338076416403
    0.4737987464759499
    0.5743723993655294
    0.4811882192734629
    0.07753282226622105
    0.11416710214689374
    0.1270705321803689
    0.15759771666489542
    0.16906401910819113
    0.6846413582097739
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    使用 seedrandom.js 生成随机数

    seedrandom.js 是 David Bau 为种子随机数生成器 (RNG) 设计的库,可在 NPM 和 CDNJS 上使用。 对于本文,我们将使用 CDNJS。

    使用 Seedrandom.js 时请记住以下几点。

    1. 您使用 new Math.seedrandom('seed key') 初始化 seedrandom。
    2. 您可以使用 Seedrandom 的 quick() 函数来生成 32 位随机数。
    3. Seedrandom.js 的 int32() 函数返回一个 32 位有符号整数。
    4. 调用不带参数的 seedrandom 会导致创建一个自动播种的基于 ARC4 的 PRNG。 自动播种使用一些值,如累积的局部熵。
    5. Seedrandom 可以将一个对象作为第二个参数。 这个对象是 {entropy: true},结果是不可预测的。
    6. 在不使用 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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    输出:

    0.08103389758898699
    
    • 1

    我们可以将种子与累积的熵混合。 您需要传递 {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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    输出:

    0.8478730572111559
    0.963664252064149
    0.6002684820777331
    0.4026776455839767
    0.7579996916288508
    
    • 1
    • 2
    • 3
    • 4
    • 5

    此外,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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    输出:

    With quick(): 0.249648863915354
    With int32(): -550219731
    
    • 1
    • 2
  • 相关阅读:
    我的网站被攻击了,运维大佬给了我自动封禁ip的脚本。
    分布式文件系统-minio
    git push报错:[remote rejected] tisco -> tisco (pre-receive hook declined)
    CMMI2.0之我见-过程质量保证PQA
    计讯物联外贸公司--佰沃恩应邀出席第三届“嘉庚论坛”—科技创新推动经济高质量发展分论坛
    Java笔记-使用processBuilder调用shell(Linux)
    要学习使用 calib3D 模块在图像中创建 3D 效果-姿势估计
    Spring框架原理 | IOC/DI | Bean
    新消费时代,零售业的进与退?
    Hangfire Pro 2022-08-31 update
  • 原文地址:https://blog.csdn.net/fengqianlang/article/details/131069794