スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

範囲乱数公式の説明が無かったので自分用に書いておこうww

範囲乱数公式とは何か?
結論から言いますと、ある範囲の乱数を得ると言う事です。

今回は、具体的にサイコロの目である1~6までを返すプログラムで考えて行きます。

[ 範囲乱数公式 ]
最小値 + (int)( rand() * (最大値 - 最小値 + 1.0) / (1.0 + RAND_MAX) )
上記の公式で、ある範囲の乱数を求められます。
最小値は、乱数の最小値であり、最大値は、乱数の最大値を指定することになります。

これから上記の説明をしていきますが、式を少しずつ分解した状態で見て行きたいと思います。

次の式を見て下さい
rand() / RAND_MAX ・・・①

上記の式では、「0~1」までの値が返ってきます。
当然と言われれば当然でしょう。
rand()の値が0の時は当然0です。
また、rand()が取りうる値の最大値を返した場合、「RAND_MAX」自体がrand()の取りうる値の最大値を格納してういるので、割った値は1です。
rand()が、0~取りうる値の最大値までの値を返せば、割った答えは「0~1」と言う値が出ます。
よって、①式の値の範囲は「0~1」です。

①式では、サイコロの目の表現には程遠いです。
そこで次に考えるのが、サイコロの目である1~6までの範囲です。
次の式で幅を設定します。
rand() * (最大値 - 最小値 + 1.0) / RAND_MAX ・・・②

おいおい、「(最大値 - 最小値 + 1.0) ・・・②’」この式なんだよ! って思われた方いますと思いますが、落ち着いてください。
ここでは、サイコロの目である1~6までを乱数で得ようとしているので、最大値-最小値は分かるかと思います。 じゃあ、何故1足すの???

②式を分かりやすいように計算の順番を入れ替えてみると次のようになります。
※式を入れ替えることによって生じる誤差については無視できるものとします。
rand() / RAND_MAX * (最大値 - 最小値 + 1.0) ・・・②’’

これならわかるかと思います。
②’の値は、最大値6,最小値1なので6になります。

①式に②’を掛けています。
よって、①式が取りうる範囲である「0~1」が②’式を掛けることによって「0~6」までの値を取れることになります。

あれ、ここまで来れば、後は1足せば行けそうなのにそうすると範囲が「1~7」になってしまうよ~
そこでようやく、「(1.0 + RAND_MAX) ・・・③’」の出番です。
②式に③’を入れると
rand() * (最大値 - 最小値 + 1.0) / (1.0 + RAND_MAX) ・・・③

になります。
ああ、折角分かりかけてたのに・・・
全然分からなくなってしまったじゃないか!!!
と思った方落ち着いてください。
③の式が難しく感じるならこれはどうでしょうか?
rand() / (1.0 + RAND_MAX) ・・・③’’

①式と何が違うかと言いますと、「RAND_MAX」に1を足すことによって、③’’式の値が取りうる範囲は次のように変化します。
「0~0.9999・・・」実際は1に限りなく近くはなりますが、1の値は取りません。
何故なら、rand()が最大値をとっても「1.0 + RAND_MAX」の方が大きくなるためです。

ここまで来れば終盤ですので頑張ってください。
では、何故③’’で範囲を「0~0.9999・・・」にしたのかと言いますと、②式の説明の後に赤字で書いてある分があると思いますが、②式の範囲だと「0~6」まで取ってしまいます。
今回説明してきましたが、「(1.0 + RAND_MAX)」をすることによって、③式の値では「0~5.999・・・」の値の範囲までしか取りません。
要するに6の値は取らないということになります。

そして、もう大詰めですが、次に以下のようにします。
(int)( rand() * (最大値 - 最小値 + 1.0) / (1.0 + RAND_MAX) ) ・・・④

③式に(int)をつけてキャストしますと④式になります。
④式にする意味ですが、③式では値の範囲が「0~5.99999・・・」を取りますが、④式では「0~5」までしか取りません。
これは、(int)でキャストすることによって、小数点以下が切り捨てられるためです。

やっと最後になります
最小値 + (int)( rand() * (最大値 - 最小値 + 1.0) / (1.0 + RAND_MAX) ) ・・・公式

④式に最小値を足すことになっていますが、これでようやく範囲としては「1~6」までの値を取ります。
以上で説明を終わりますが、説明の順番を変えた方がいいかなと書き終わってから思ったりしました。

※コラム より精度を高くするには?「(1.0 + RAND_MAX)」
ここまで説明していて気付いたかもしれませんが、「RAND_MAX + 1」をするのは、③’’式の値が取りうる範囲を0以上であり限りなく1に近づけるが1を取らないようにするためにしています。
なら、rand()の最大値より微妙に大きい数字でもいいのではないか?
という疑問が起こった方がいらっしゃると思います。
それは正解です。
実際問題の精度で言うなら、1よりも0.1を足した方が当然1に近づきます。
精度を気にする方なら、③’’式を次のようにする方もいるかもしれません
rand() / (0.1 + RAND_MAX) ・・・③’’’

以下に、1~6までの乱数を1つ表示するサンプルを書いてみました。
srand()関数やプリプロセッサーの説明など、下記のソースに関しては説明を省略しますが、間違などありましたらコメントなりでお知らせいただければ助かります。


 
#include   <stdio.h>
#include   <stdlib.h>
#include   <time.h>

#define MIN 1
#define MAX 6

int main()
{
	srand((unsigned int)time(NULL));

	printf("%d\n", MIN + (int)(rand()*(MAX-MIN+1.0)/(1.0+RAND_MAX)));

	return 0;
}


範囲乱数公式 につきましては、以下のサイトにて使い方などが載っております。
下記のサイトでは使い方のみで説明が載っていなかったので、忘却防止も兼ねてメモ的な形で書きました。

http://homepage3.nifty.com/mmgames/c_guide/21-02.html#S3

テーマ : プログラミング
ジャンル : コンピュータ

コメントの投稿

非公開コメント

No title

乱数作成のために参考させていただきました。
わかりやすい解説でした。

>ミネ様

お役に立てたようで大変うれしいです。
今後とも何かあればよろしくお願いします<m(__)m>
プロフィール

agpm

Author:agpm
最近は、ゲーム中心にやっています。
アニメなども見てますが、そこまで詳しくはないです<(_ _)>
更新は気分しだいで、頻度にはかなり差があります

リンクフリーなのでどんどんして頂けると管理人はうれしいです
相互リンクでもOK


連絡こちら↓
メールフォームはここ

PCのスペック公開

リンク
カレンダー
01 | 2017/03 | 12
- - - 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 -
最新コメント
月別アーカイブ
カテゴリ
RSSリンクの表示
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。