質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

2回答

3207閲覧

C言語で、毎回違う乱数を生成する方法

harug

総合スコア28

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2022/01/30 08:18

編集2022/01/30 08:50

前提・実現したいこと

C言語初心者です。
二重のfor文の中でrand()関数を使用して簡単なコードを書いたのですが、乱数の出力が2回目以降から一定の値となってしまいます。。
funcAとfuncBの中では、srand((unsigned int)time(NULL));で乱数の種を再設定して、funcAとfuncBにアクセスした際は毎回、違う値を返すようにしたいです。

該当のソースコード

C言語

1#include <stdio.h> 2#include <stdlib.h> 3#include <time.h> 4 5 6double funcA(int n){ 7 srand((unsigned int)time(NULL)); 8 int r = rand() % n; 9 10 return r; 11} 12 13 14double funcB(int n){ 15 int r; 16 srand((unsigned int)time(NULL)); 17 r = rand() % n; 18 19 return r; 20} 21 22 23int main(){ 24 int i,j; 25 double rnd; 26 int num; 27 double epsilon = 0.05; 28 29 unsigned int seed = 10;//私の都合でここは固定したいです 30 31 /* i試行 */ 32 for(i=1; i<=3; i++){ 33 srand(seed); 34 35 rnd = (double)rand()/(double)RAND_MAX; 36 37 if(epsilon <= rnd){ 38 num = funcA(5); 39 }else{ 40 num = funcB(2); 41 } 42 43 printf("-----------結果-----------\n"); 44 45 printf("%lf\n", rnd); 46 } 47 printf("\n\n"); 48 return 0; 49}

ちなみに、メイン関数の中で定義したseedの値をsrand((unsigned int)time(NULL));にすれば解決なのでしょうが、ここ私の都合上10のままで、funcAとfuncBにアクセスしたときのみ毎回違う値を返すようにしたいです。

実行した結果は

-----------結果----------- 0.002167 -----------結果----------- 0.832820 -----------結果----------- 0.832820 -----------結果----------- 0.832820 -----------結果----------- 0.832820

このようになってしまい、二回目以降の結果が一定になってしまいます。

試したこと

C言語

1 if(epsilon <= rnd){ 2 num = funcA(5); 3 }else{ 4 num = funcB(2); 5 }

この部分をコメントアウトして実行すると、毎回違う値は出力されました。
また、funcAとfuncBの中のsrand((unsigned int)time(NULL));をコメントアウトしても上手くいきました。
しかし、これだと乱数の種が一定なので、funcAとfuncBへの一回目のアクセス時は毎回同じ値になってしまいます。

恐らく、メイン関数でもfuncA、funcBでもsrand関数を使用しているためおかしくなっているのではないかと考えます。

funcAとfuncBへのアクセスで毎回違う値を返すようにするためにはどのようにすればよろしいでしょうか。
お力添えをお願いします。

補足情報(FW/ツールのバージョンなど)

VScode

バージョン: 1.63.2

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

srandで同じ数字を指定しているなら常に同じ乱数列が生成されます
これはそういうもんなのでどーしよーもないです

投稿2022/01/30 09:18

y_waiwai

総合スコア88163

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

harug

2022/01/30 10:25

回答ありがとうございます。 この場合、メイン関数のseedは10に固定したまま、疑似的にfuncA、funcBから毎回違う乱数を引っ張てくることはできますか。
y_waiwai

2022/01/30 12:15

もいちど別にseedを実行しましょう #意味あるのかわからんけど
harug

2022/01/30 16:22

ありがとうございます。 rand_r()を使って試してみたのですが、どうやらWindowsではサポートされていないらしく、 何かWindows上でrand_r()と同様に機能する関数はございますでしょうか。
guest

0

ベストアンサー

srandは、「これ以降、この数字を起点として乱数を発生しろ」という関数なので、1秒以内に秒単位の時刻を引数に呼び出すと、その直後ではrandは常に同じ値を返すことになります。

ということで、普通はsrandはプログラムの最初で一度だけ呼び出します。

コメントを受けての追記。

C

1前略 2unsigned int seed2; 3 4double funcA(int n){ 5 int r = rand_r(&seed2) % n; 6 return r; 7} 8double funcB(int n){ 9 int r; 10 r = rand_r(&seed2) % n; 11 return r; 12} 13int main(){ 14 int i,j; 15 double rnd; 16 int num; 17 double epsilon = 0.05; 18 19 unsigned int seed = 10;//私の都合でここは固定したいです 20 seed2 = (unsigned int)time(NULL); 21 22 /* i試行 */ 23 for(i=1; i<=3; i++){ 24 25 rnd = (double)rand_r(&seed)/(double)RAND_MAX; 26後略

投稿2022/01/30 08:39

編集2022/01/30 14:36
otn

総合スコア86307

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

harug

2022/01/30 10:25

回答ありがとうございます。 この場合、メイン関数のseedは10に固定したまま、疑似的にfuncA、funcBで毎回違う乱数を引っ張てくることはできますか。
otn

2022/01/30 10:54 編集

ああ、ようやく意味がわかりました。 1つの系列を固定しておいて、それと別に毎回異なる系列を持ちたいと言うことですね。 srand+randだと、seedをライブラリ側に保存するので駄目です。 seedをこっち側で持つrand_rを使いましょう。 https://linuxjm.osdn.jp/html/LDP_man-pages/man3/rand.3.html メイン用の seed1の初期値を10にして、その他用の seed2=time() にすればいいかと。 seed2はグローバル変数でいいかと思います。 あるいはこういう関数を使うか。 https://linuxjm.osdn.jp/html/LDP_man-pages/man3/drand48_r.3.html
harug

2022/01/30 14:08

ありがとうございます。調べてみたのですがいまいちわかりませんでした。。 seed2をグローバル変数で定義しようとすると「定数式では関数の呼び出しを使用できない」とエラーが出てしまいます。 seed2のグローバル変数定義の仕方、 また、funcA、funcBでのrand_r()を使うための記述の仕方を簡単に教えていただけますとありがたいです。
otn

2022/01/30 14:29

えー、何がわからないのかわかりませんが、追記しておきます。
harug

2022/01/30 15:19

ありがとうございます。参考にさせていただきました。 エラーは出ないのですが、以下のような警告が出てしまい、コンパイルされず、実行ファイルが作成されません。 warning: implicit declaration of function 'rand_r'; did you mean 'rand'? [-Wimplicit-function-declaration] int r = rand_r(&seed2) % 2; ^~~~~~ rand この警告を無視することはできないでしょうか。
otn

2022/01/30 15:27

警告であれば実行ファイルは生成されるので、エラーが出ているのでは? お使いの環境で rand_r が無いのかもしれません。 Linuxにはありますが、Windowsにはなさげですね。
harug

2022/01/30 15:49

なるほど。 記載し忘れておりました。Windowsの環境で実行しています。 代わりにrand_s()を使うととりあえずは、実行ファイルが作成されました。 しかし、rndの値がずっと0で出力されてしまいます。 これは、やはりrand_s()が原因でしょうか。
otn

2022/01/30 15:51

意味の違う関数を使ったら駄目に決まっています。
harug

2022/01/30 16:03

何かWindows上でrand_r()と同様に機能する関数はございますでしょうか。
otn

2022/01/31 04:08

軽くググった感じでは無さそうですね。 代用策としては、seed=10の系列の乱数をあらかじめたくさん生成してファイルに書いておき、 seed=10の系列の乱数が欲しい時は、randを呼ぶんじゃなくてそのファイルから読む。 あとは、Windowsの中にLinux環境を作るか。
fana

2022/02/01 01:48

> C言語で は must なのでしょうか? C++ にしても良いなら <random> を使えば解決しそうに見えますが…?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問