• ベストアンサー

型変換??

int RANDOM_FUNCTION( int n ) { return (int)( rand() / (float)RAND_MAX * n ); } について Q1.この関数は0からn-1までの乱数を作るそうなのですが,何故ですか? 0<=rand()<=RAND_MAX だから0からnまでの乱数ができるような気がするのですが. Q2.RAND_MAXではなく(float)RAND_MAXとキャストしてある意味は何ですか? Q3.srand((unsigned)time(NULL));と srand((unsigned int)time(NULL));では何か違いますか? Q4.  static int first = 0; if (first == 0){ srand((unsigned)time(NULL)); first = 1; } という処理でsrand((unsigned)time(NULL));は最初の一回だけ呼び出されるようになっているようですが,この部分を srand((unsigned)time(NULL)); というように毎回呼び出すようにするとどうなりますか? 一回呼び出すだけで乱数系列の初期値が呼び出される時に変化しているのですか? Q5.この関数とは関係ない質問ですが,例えば a:int型 b:int型 c:double型 d:float型 のとき d = a / b + c という演算は 1 a:int型,b:int型より(a / b)の結果はint型(小数になった場合は小数点以下切り捨て) 2 (a / b):int型,c:double型,int<doubleより (a / b + c)の結果はdouble型 3 d:float型,『=のあるときは左辺の型に合わせる』よりdはfloat型 というように型変換されているという解釈でいいのでしょうか??

質問者が選んだベストアンサー

  • ベストアンサー
  • liar_adan
  • ベストアンサー率48% (730/1515)
回答No.2

>Q1.この関数は0からn-1までの乱数を作るそうなのですが,何故ですか? >0からnまでの乱数ができるような気がするのですが. 実際に試してみましたがその通りのようです。 ほとんどの場合に0~n-1を返し、 ごく希に(RAND_MAXが出たときに)nを返します。 100回や1000回ではnは出ないかもしれませんが、もっと多くすると出てきます。 これを書いた人のミスだと思います。 身近な人なら指摘してあげてください。 書籍ならば書名を教えてください。 ある本(CプログラミングFAQ、参考URL参照)によると、 0~N-1の乱数を発生する方法は (int)((double)rand() / ((double)RAND_MAX + 1) * N) であるとありました。 これは (int)(rand() / (RAND_MAX + 1.0) * N) と書いても実質同じになります。 ただ、私はここで浮動小数点に変換する意味がわかりませんでした。 (rand() * n) / (RAND_MAX+1) としてもよさそうなものです。 これはおそらく、昔はintの最大値とRAND_MAXがほぼ同じだったので、 整数計算のオーバーフローを心配したのだと思います。 intの最大値がRAND_MAXよりはるかに大きく、 使うnが100ぐらいなら、 (rand() * n) / (RAND_MAX+1) と書いても大丈夫だと思います。(たぶん) >Q4. そういうミスをしてしまったことがあります。 ループでそれをやると、 一秒の間、何度も同じ値が返されて、ぜんぜん乱数になりませんでした。

参考URL:
http://www.catnet.ne.jp/kouno/c_faq/c13.html#15
Rossana
質問者

お礼

実際に試してみて頂き,確信の持てる回答ありがとうございます.やはりミスなのですね. 書名は挙げてもこのサイトの違反?にはならないでしょうか. いちお違反にならない?程度に言いますと技術評論社さんの本です. >これはおそらく、昔はintの最大値とRAND_MAXがほぼ同>じだったので、整数計算のオーバーフローを心配した >のだと思います。 なるほどです. URLも参考になりました.

その他の回答 (4)

  • HOGERA3
  • ベストアンサー率35% (50/139)
回答No.5

No.3です。 >>(rand() * n) / (RAND_MAX+1) >>としない理由ですが、これだと必ず0になるからでは >>ないでしょうか。 > >ならないよ~。私は実際に使ってみたんだから。 ... >(rand() / (RAND_MAX+1)) * n >なら必ず0になるけど。 そうですね。 (rand() / (RAND_MAX+1)) * n と勘違いしてました。 >また、プログラム中に >1.0 >のように少数が出てくると、 >これはdoubleの型を持つものとされます。(floatではありません) そうなんですか。知りませんでした。 インチキばかり語ってしまって申し訳ございません。

Rossana
質問者

お礼

いやいや人は誰でもミスはするものです. 一生懸命回答して下さった事に感謝です. 逆にこのミスによってその二つの式の意味 (ニュアンス?)がより分かりやすくなったんですよ! やはり失敗がなければ理解は深まりません. 問題がなければ解決ということは生まれないですね! ありがとうございました. みなさんの総合的な回答によってよくわかりました. もっとプログラミングを勉強して自由自在に操れるようになろうと思います.

  • liar_adan
  • ベストアンサー率48% (730/1515)
回答No.4

>(rand() * n) / (RAND_MAX+1) >としない理由ですが、これだと必ず0になるからでは >ないでしょうか。 ならないよ~。私は実際に使ってみたんだから。 「だって私は見たんですから!」((C)神田山陽) (rand() / (RAND_MAX+1)) * n なら必ず0になるけど。 型変換の基本は、「広い方にあわせる」です。 広い方というのは、表現できる数の範囲が広い方です。 long double型と、それ以外の型の計算は、long double型になり、 double型と、long double以外の型の計算は、double型になり、 float型と、doubleおよびlong double以外の型の計算は、float型になります。 またlong型とint型の計算はlong型になります。 (整数の計算はunsignedが付くとややこしくなるけれど、それは省略) 例外はcharとかshortとかであって、 これらは一回int型になおしてから計算されます。 だから char a, b; としたとき、a * bの型はintになります。 定数にも型があります。 たとえば、RAND_MAXは、ヘッダファイルの中で0x7FFFとか32767とか、 定まった数値で#defineされています。 こういう場合、普通はint型になります。 intの範囲を超えた場合、longになる場合もあります。 また、プログラム中に 1.0 のように少数が出てくると、 これはdoubleの型を持つものとされます。(floatではありません) RAND_MAX+1.0 の型は、(RAND_MAXがintとすると) intとdoubleでdouble型となります。 そのあと、割り算や掛け算をしても、広い方にあわせるので 最終的な型はdoubleとなります。

Rossana
質問者

お礼

詳しい説明ありがとうございます. 分かりやすかったです!! ((C)神田山陽)って知らなくてすいませんf^^; そのセリフ有名なんですかね~?

  • HOGERA3
  • ベストアンサー率35% (50/139)
回答No.3

ちょっと遅いレスですがとりあえず。 (rand() * n) / (RAND_MAX+1) としない理由ですが、これだと必ず0になるからでは ないでしょうか。 (int / int = int ですから) (rand() * n) / (RAND_MAX+1.0) ならば、int / float = float なので n*0.xxxx になって0~nまでの整数が得られる。 ってことだと思います。

Rossana
質問者

お礼

回答ありがとうございます. さっそくですが,補足回答よろしくお願いします.

Rossana
質問者

補足

HOGERA3さんの回答によると RAND_MAXの型は RAND_MAX+1 と RAND_MAX+1.0 という書き方の違いによって決まってしまうということでしょうか? #defineでRAND_MAXは定義していますが,この型はどうなるかふと疑問だったのですが,型はこのようにまわりの環境に左右されるということでしょうか?

回答No.1

(A1) コンパイラや使用環境によって変わると思うのですが、例えば RAND_MAX == 1000 だったとします。0 ~ 100 の乱数が欲しくても ( n == 100 )、そのままだと 101 ~ 1000 の整数も発生してしまいます。 rand() / (float)RAND_MAX * n とすると、 最小値 : 0 / (float)RAND_MAX * n == 0 最大値 : RAND_MAX / (float)RAND_MAX * n == n ( n - 1 じゃなくて、n ですよね?) となるので、0 ~ n の乱数を得ることができます。 (A2) キャストなしだと RAND_MAX が int とみなされて、途中の計算で四捨五入が起きてしまうからですね。一度キャストなしでやってみるとわかると思います。 (A3) 同じでしょう。 (A4) rand() は、乱数は乱数でも、あくまで擬似乱数なので、例えば、srand(100) としたときの rand() の1回目、2回目、3回目・・・の値は、今日実行しても、明日実行しても、いつでも、常に同じ組み合わせです。(実際にやってみるとわかります。)同じ組み合わせにならないように srand() のパラメータに time() を渡しているわけですが、毎回 srand() を呼び出すと、毎回、乱数系列が変わるので、もしかすると rand() が返す整数の分布が均一にならないかもしれませんね。確率がかかわる問題を解く(モンテカルロ・シュミレーションなど)なら、通常どおり、srand() は最初の1回だけ呼ぶようにした方が無難だと思います。 (A5) そういう解釈でいいんじゃないでしょうか。別の質問にした方がよかったような気がしますが・・・。

Rossana
質問者

お礼

回答ありがとうございました. 計算時RAND_MAXは一度intとみなされるんですね!

Rossana
質問者

補足

>(A2) キャストなしだと RAND_MAX が int とみなされ >て、途中の計算で四捨五入が起きてしまうからです >ね。一度キャストなしでやってみるとわかると思いま >す。 四捨五入は小数点以下切り捨ての間違いでしょうか?  rand() / RAND_MAX * n とキャストなしだとrand() / RAND_MAXの部分が0.…って小数になりこれはint型だから小数点以下切り捨てで0ってなってこれにnをかけても乱数は0しか出てこないということでいいでしょうか?

関連するQ&A