メルセンヌ・ツイスタの乱数生成範囲指定

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
KKKK

メルセンヌ・ツイスタの乱数生成範囲指定

#1

投稿記事 by KKKK » 11年前

メルセンヌ・ツイスタで乱数の生成範囲を指定したいのですが

以下の方法(1),(2)以外でもっと厳密に一様乱数を生成できる方法がわかる方いますか?
(1)
int n;

n = genrand_int32() % 100;

(2)
int n;

n = (genrand_real3() * 100);

上記の方法では一様乱数ではなく、必ず偏りが生じてしまいます。

分かる方いましたら宜しくお願いします。

うずら

Re: メルセンヌ・ツイスタの乱数生成範囲指定

#2

投稿記事 by うずら » 11年前

整数型の場合。
得た乱数の値と、得られる乱数の最大値を除算を利用して0.0~1.0の範囲にスケーリングして、
得たい値の最大値と掛けてintにキャストして返す。
実数型の場合はintを全部doubleに書き換えれば。

コード:

int GetRand32(int pGetMax)
{
  const double getrand_int32Max = ; // genrand_int32() の最大値。除算のためdouble

  return int(genrand_int32() / getrand_int32Max * pGetMax);
}

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: メルセンヌ・ツイスタの乱数生成範囲指定

#3

投稿記事 by みけCAT » 11年前

うずら さんが書きました:整数型の場合。
得た乱数の値と、得られる乱数の最大値を除算を利用して0.0~1.0の範囲にスケーリングして、
得たい値の最大値と掛けてintにキャストして返す。
実数型の場合はintを全部doubleに書き換えれば。

コード:

int GetRand32(int pGetMax)
{
  const double getrand_int32Max = ; // genrand_int32() の最大値。除算のためdouble

  return int(genrand_int32() / getrand_int32Max * pGetMax);
}
この方針では偏りが生じます。(例えば0~5の値が出る乱数を用いて、0~3の乱数を出すことを考えるとわかる)
偏りが生じないようにするには、半端な部分の値が出たらそれを棄却して乱数を取得しなおすと良いです。
参照:いつからその方法で偏りのない乱数が得られると錯覚していた? - アスペ日記

コード:

#include <stdio.h>
#include "mt19937ar.h"

unsigned int rand_uniform(unsigned int max) {
	/* 「余り」の数を求める */
	unsigned int reject=0xffffffff%max;
	unsigned int randnum;
	reject=(reject+1)%max;
	do {
		randnum=genrand_int32();
	} while(randnum<reject);
	return (unsigned int)((double)(randnum-reject)*max/(4294967296.0-reject));
}

int main(int argc,char* argv[]) {
	int i;
	unsigned int max=10;
	if(argc>=2)sscanf(argv[1],"%u",&max);
	for(i=0;i<100;i++) {
		printf("%u\n",rand_uniform(max));
	}
	return 0;
}
このプログラムは、よく検証していないのでバグがあるかもしれません。
上にあげたサイトのプログラムの、rand()をgenrand_int32()に、RAND_MAXを0xffffffffuに置き換えたものも利用できます。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

閉鎖

“C言語何でも質問掲示板” へ戻る