시드를 사용하여 JavaScript에서 난수 생성

Habdul Hazeez 2023년10월12일
  1. 시드와 SFC32를 사용하여 난수 생성
  2. 시드와 Mulberry32를 사용하여 난수 생성
  3. 시드와 Xoshiro128**을 사용하여 난수 생성
  4. 시드와 JSF를 사용하여 난수 생성
  5. seedrandom.js를 사용하여 난수 생성
시드를 사용하여 JavaScript에서 난수 생성

이 기사에서는 시드를 사용하여 PRNG에서 난수를 생성하는 방법을 다룹니다. 한편, PRNG의 시드가 높은 엔트로피를 갖도록 하는 것이 가장 좋습니다.

따라서 해싱 함수를 사용하여 시드를 생성합니다. 그런 다음 시드를 PRNG에 전달합니다.

시드와 SFC32를 사용하여 난수 생성

‘SFC32’ 또는 Simple Fast Counter는 ‘PractRand’(대부분 C)의 빠른 PRNG이며 128비트 상태의 JavaScript로 구현되며 매우 빠릅니다. ‘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를 사용하여 5개의 난수를 생성합니다.

암호:

// 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** 생성기를 개발했습니다. xorshift128Xorshift 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는 빠른 생성기인 JSF(Jenkins Small Fast) 생성기를 만들었습니다. 그러나 SFC32와 비교할 때 빠르지는 않습니다.

JSF 코드를 관찰하면 SFC32와 유사함을 알 수 있습니다. JSF는 난수를 생성하기 전에 시드 이상을 취할 수 있습니다.

다음 코드에서 시드와 JSF로 10개의 난수를 생성합니다.

암호:

// 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는 시드된 난수 생성기(RNG)용으로 설계된 David Bau의 라이브러리이며 NPM 및 CDNJS에서 사용할 수 있습니다. 이 문서에서는 CDNJS를 사용합니다.

Seedrandom.js를 사용할 때 다음 사항에 유의하십시오.

  1. new Math.seedrandom('seed key')을 사용하여 seedrandom을 초기화합니다.
  2. Seedrandomquick() 기능을 사용하여 32비트 임의성을 생성할 수 있습니다.
  3. Seedrandom.js의 int32() 함수는 32비트 부호 있는 정수를 반환합니다.
  4. 인수 없이 seedrandom을 호출하면 자동 시드 ARC4 기반 PRNG가 생성됩니다. 자동 시딩은 누적된 로컬 엔트로피와 같은 일부 값을 사용합니다.
  5. Seedrandom은 개체를 두 번째 인수로 사용할 수 있습니다. 이 개체는 {entropy: true}이며 결과를 예측할 수 없습니다.
  6. new 키워드 없이 Math.seedrandom을 호출하면 기본 Math.random()이 대체됩니다. 교체는 new 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

축적된 엔트로피와 시드를 혼합할 수 있습니다. seedrandom의 두 번째 인수로 {entropy: true}를 전달해야 합니다.

암호:

<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
Habdul Hazeez avatar Habdul Hazeez avatar

Habdul Hazeez is a technical writer with amazing research skills. He can connect the dots, and make sense of data that are scattered across different media.

LinkedIn

관련 문장 - JavaScript Number