ttki's diary

プログラミング好きな人の日記です

色々な乱数

暗号について調べているうちに、乱数が必要になったのでしらべてみました。

乱数とは、5,2,7,3,7,9... のように次の数が予測できないバラバラな数。ですが、
コンピューターで乱数を得るときは、よっぽどのことがない限り、擬似乱数という計算によって
得られる乱数を使います。(計算によって得るので、予測ができる)
擬似乱数には周期があり、しばらく使っていると、また同じ数列が出てきてしまうことがあります。
この周期が長いほどいいといわれています。
ガイガーカウンタとかがあれば真の乱数が得られますけどね^^

ということで、C/C++ C# などで使えそうな擬似乱数アルゴリズムをまとめました。

・stdlib rand()

C/C++ 標準ヘッダのstdlib(cstdlib)内の rand()関数 です。
  0...RAND_MAX までの乱数を返します。
  アルゴリズム線形合同法なので、周期が短いのが欠点です。(2^32 ぐらい)

C# System.Random.Next()

System.Random 内の Next()関数です。
  C/C++ のrand() よりは多少いいものの、満足のいくものではありません。
  どんなアルゴリズムを使っているかは、わかりませんでした。(ググってくださいww)

メルセンヌ・ツイスター(MT)

  自分の知っている中でもっとも周期の長い、メルセンヌ・ツイスター
  何と周期が 2^19937 - 1 もあります。
  ほぼ、無限大です。(Mersenne Twister: A random number generator (since 1997/10))

・XorShift

意外と知られていない? XorShift。その名の通り、XOR と SHIFT を使います。
  周期も 2^128 - 1 と長く、いい感じです。(計算速度も速い)

・M系列

  M系列という物もあります。メルセンヌ・ツイスターも中核部分はこれです。
  面白そうなので、コードを探していたら Wikipedia に載っていました。(線形帰還シフトレジスタ - Wikipedia)

#include <iostream>
using namespace std;
// Wikipedia にあったものを少し改造
unsigned Mrand(int Max)//Max 最高値
{
	static unsigned int lfsr = ( 1 >> 1) ^ ( -(1 & 1u) & 0xd0000001u);
	if(lfsr != 1)
	{
		lfsr = (lfsr >> 1) ^ ( -(lfsr & 1u) & 0xd0000001u);
	}
	return lfsr % Max;
}

int main(void)
{
	int i=0;
	while(i<10000)
	{
		cout << Mrand(100) << endl;
		i++;
	}
	return 0;
}

乱数って面白いですね。今度、乱数のクラスを作ろうと思います。

それでは^^