C Language
乱数生成
サーチ…
備考
rand()
欠陥のために、他の多くのデフォルトの実装が長年にわたり浮上してきました。それらの中には:
-
arc4random()
(OS XおよびBSDで利用可能) -
random()
(Linuxで利用可能) -
drand48()
(POSIXで利用可能)
基本乱数生成
関数rand()
は、 0
とRAND_MAX
( 0
とRAND_MAX
含む)の間の擬似ランダム整数値を生成するために使用できます。
srand(int)
は、疑似乱数ジェネレータのシードに使用されます。 rand()
は同じシードでシードされるたびに、同じ値のシーケンスを生成する必要があります。 rand()
呼び出す前に一度だけ播種してください。それは、擬似乱数の新しいバッチを生成するたびに、繰り返し播種したり、再播種すべきではありません。
標準的な方法は、 time(NULL)
結果をシードとして使用することです。乱数ジェネレータが確定的なシーケンスを必要とする場合は、各プログラムの開始時に同じ値でジェネレータをシードすることができます。これは一般にリリースコードでは必要ありませんが、バグを再現性のあるものにするためにはデバッグ実行に便利です。
ジェネレータをシードしない場合は、常にsrand(1)
シードされているかのように振る舞うようにしてください。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
int i;
srand(time(NULL));
i = rand();
printf("Random value between [0, %d]: %d\n", RAND_MAX, i);
return 0;
}
可能な出力:
Random value between [0, 2147483647]: 823321433
ノート:
C標準は、生成されるランダムシーケンスの品質を保証しません。過去には、 rand()
いくつかの実装では、生成された数値の分布と乱数に深刻な問題がありました。 rand()
の使用法は、暗号化のような深刻な乱数生成の必要性にはお勧めできません。
公認合同ジェネレータ
ここには、 rand()
または同様のライブラリ関数に依存しないスタンドアロン乱数ジェネレータがあります。
なぜそんなことが欲しいの?おそらく、あなたのプラットフォームの組み込み乱数ジェネレータを信頼していないかもしれません。あるいは、特定のライブラリ実装とは独立したランダム性の再現可能なソースが必要なこともあります。
このコードはpcg-random.orgのPCG32であり、優れた統計的性質を持つ近代的で高速な汎用RNGです。それは暗号では安全ではないので、暗号に使用しないでください。
#include <stdint.h>
/* *Really* minimal PCG32 code / (c) 2014 M.E. O'Neill / pcg-random.org
* Licensed under Apache License 2.0 (NO WARRANTY, etc. see website) */
typedef struct { uint64_t state; uint64_t inc; } pcg32_random_t;
uint32_t pcg32_random_r(pcg32_random_t* rng) {
uint64_t oldstate = rng->state;
/* Advance internal state */
rng->state = oldstate * 6364136223846793005ULL + (rng->inc | 1);
/* Calculate output function (XSH RR), uses old state for max ILP */
uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
uint32_t rot = oldstate >> 59u;
return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
}
void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initstate, uint64_t initseq) {
rng->state = 0U;
rng->inc = (initseq << 1u) | 1u;
pcg32_random_r(rng);
rng->state += initstate;
pcg32_random_r(rng);
}
それを呼び出す方法は次のとおりです。
#include <stdio.h>
int main(void) {
pcg32_random_t rng; /* RNG state */
int i;
/* Seed the RNG */
pcg32_srandom_r(&rng, 42u, 54u);
/* Print some random 32-bit integers */
for (i = 0; i < 6; i++)
printf("0x%08x\n", pcg32_random_r(&rng));
return 0;
}
指定された範囲に生成を制限する
通常、乱数を生成する場合、範囲内の整数、または0.0〜1.0のp値を生成すると便利です。モジュラス演算を使用してシードを低い整数に減らすことができますが、NがRAND_MAXに比例して大きくなると、小さなサイクルが頻繁に発生し、その結果、分布がわずかに歪んでしまいます。
マクロ
#define uniform() (rand() / (RAND_MAX + 1.0))
0.0〜1.0のε値を生成するので、ε
i = (int)(uniform() * N)
0からN - 1の範囲内の一様乱数にi
を設定します。
残念ながら、RAND_MAXはdouble
型の変数が正確に表すことができるという点で技術的な欠陥があります。これは、 RAND_MAX + 1.0
がRAND_MAXに評価され、関数が時々1を返すことを意味します。しかしこれはそうではありません。
Xorshift Generation
欠陥に良いと簡単に代替rand()
手続きは、xorshift、によって発見された擬似乱数生成器のクラスであるジョージ・マルサグリア 。 xorshiftジェネレータは、暗号化されていない最速の乱数ジェネレータの中でも最も高速です。より多くの情報と他の実装例は、 xorshift Wikipediaのページで入手できます。
実装例
#include <stdint.h>
/* These state variables must be initialised so that they are not all zero. */
uint32_t w, x, y, z;
uint32_t xorshift128(void)
{
uint32_t t = x;
t ^= t << 11U;
t ^= t >> 8U;
x = y; y = z; z = w;
w ^= w >> 19U;
w ^= t;
return w;
}