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

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

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

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

804閲覧

rand関数を使用した乱数を発生させた際に実行結果が毎回同じになる解消方法

mell1008

総合スコア2

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2024/08/29 04:09

実現したいこと

□プログラム概要
・10回のループの中で、内角、外角、真ん中をランダムに発生させて
それぞれ出たコースの数を出力
・1が出たら真ん中
・2が出たら外角
・3が出たら内角

発生している問題・分からないこと

プログラムは正常に動くが、実行結果が以下内容で何度やっても同様の出力結果になる
検索したところrand()関数は疑似乱数を発生させるため同様の結果になっているのか?
といった仮説までは立てれたが、実際にランダムに結果を出力させる実行方法が分からないです。

【実行結果】
1球目
真ん中:0,外角:0,内角:0
2球目
真ん中:0,外角:0,内角:1
3球目
真ん中:0,外角:0,内角:2
4球目
真ん中:0,外角:1,内角:2
5球目
真ん中:0,外角:2,内角:2
6球目
真ん中:0,外角:2,内角:3
7球目
真ん中:0,外角:3,内角:3
8球目
真ん中:1,外角:3,内角:3
9球目
真ん中:2,外角:3,内角:3
10球目
真ん中:2,外角:4,内角:3
10球中真ん中:2球、外角:4球、内角:4球

該当のソースコード

#include<iostream> #include<stdlib.h> using namespace std; int main(int argc, char** argv) { int out=0, in=0, center=0;//投げたコースを格納 int zone;//コースを格納 int count;//ループ用変数 for (count = 0; count < 10; count++) {//10球投げるまで繰り返す zone = 0; cout << count + 1 << "球目" <<endl<<"真ん中:" << center << ",外角:" << out << ",内角:" << in << endl; zone=rand() % 3 + 1;//コースを乱数から格納する if(zone==1){//zoneが1なら真ん中でカウント center = center + 1; } else if (zone == 2) {//zoneが2なら外角でカウント out = out+1; } else {//zoneが3なら内角でカウント in = in + 1; } } //結果を表示 cout <<count <<"球中" << "真ん中:" << center << "球、外角:" << out << "球、内角:" << in << "球" << endl; }

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

わからないことや発生している問題を教えてください
上記に実行結果を記載

補足

特になし

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

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

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

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

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

guest

回答2

0

Windows 11、Visual Studio 2022で確認しました。
srandとrandで何の問題もありませんが、タグがC++なので、C++の方法を書きます。

C++で乱数を発生させる方法は、いくつかありますが、今回は1~3のどれかを発生させるので、std::uniform_int_distributionを使用します。

(参考)
https://cpprefjp.github.io/reference/random.html
https://cpprefjp.github.io/reference/random/uniform_int_distribution.html

#include <iostream> // 1行変更 #include <random> using namespace std; int main(int argc, char** argv) { int out=0, in=0, center=0;//投げたコースを格納 int zone;//コースを格納 int count;//ループ用変数 // 3行追加 random_device seed_gen; default_random_engine engine(seed_gen()); uniform_int_distribution<> dist(1, 3); for (count = 0; count < 10; count++) {//10球投げるまで繰り返す zone = 0; // 1行変更 zone=dist(engine);//コースを乱数から格納する if(zone==1){//zoneが1なら真ん中でカウント center = center + 1; } else if (zone == 2) {//zoneが2なら外角でカウント out = out+1; } else {//zoneが3なら内角でカウント in = in + 1; } // 1行移動 cout << count + 1 << "球目" <<endl<<"真ん中:" << center << ",外角:" << out << ",内角:" << in << endl; } //結果を表示 cout <<count <<"球中" << "真ん中:" << center << "球、外角:" << out << "球、内角:" << in << "球" << endl; }

投稿2024/08/31 05:45

hiroki-o

総合スコア1117

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

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

mell1008

2024/08/31 08:00

hiroki-o様 ご回答いただきありがとうございます。 私の環境でもいただいた内容で実行してみたのですが、問題なく出力されました! 1点質問させていただきたいのですが追記いただいた以下の4行は、乱数を発生させると時に(1,3)の箇所以外は決まったコードになるのでしょうか?(おまじないのようなもの?) random_device seed_gen; default_random_engine engine(seed_gen()); uniform_int_distribution<> dist(1, 3); zone = dist(engine);
hiroki-o

2024/08/31 08:22

そうです。おまじないだと思っていいです。 ただし、もう少し詳しく言うと、default_random_engineは他のエンジンに差し替えできます。 最初のリンクの「パラメータ定義済み擬似乱数生成器」を見てください。 uniform_int_distributionは、intの乱数なら、これでよいです。 他の型の場合は、最初のリンクの「分布生成器」を見てください。
mell1008

2024/08/31 12:30

ご返信いただきありがとうございます。 大変勉強になりました。 今回は整数値になりますが、実数値になるとuniform_real_distributionといった宣言に変更が必要だと理解しました。 今後、実装する内容によっていただいたアドバイスを基に学習致します!
guest

0

ベストアンサー

srand関数を使用して乱数生成の初期値を与えると良いかと思います

参考)
https://qiita.com/ohwada/items/08af887748aa6a034c47
https://www.sejuku.net/blog/25352

投稿2024/08/29 04:14

AbeTakashi

総合スコア4853

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

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

mell1008

2024/08/29 04:50

ご回答いただきありがとうございます。 srand関数とtime関数を使用し、乱数をランダムに発生させることができたかと思うのですが、 time関数は1秒間で更新されるため#include<unistd.h>のsleep関数を使用して時間を置こうとしました。 そうするとwindows環境で実行しているためインクルードエラーになってしまいます。 ディレクトリのプロパティ設定など解決方法を試してみたのですが解決ができず、、、 上記問題を解決する方法はございますでしょうか? お手数をおかけしますがご確認よろしくお願い致します。
fana

2024/08/29 05:00

> time関数は1秒間で更新されるため… どういう状況下で何が問題となっているのかを具体的に述べた方がよいのではないかと見えます. (このプログラムの実行を1秒間に何回も実施する みたいな話なのですか?)
fana

2024/08/29 07:13 編集

C++ならば, C++で乱数シードを得るのによく使われている(ように見える) std::random_device なるものを用いるのではどうでしょうか?(↓こんな感じ?) {//rand()の擬似乱数系列初期化 std::random_device SeedSource; srand( SeedSource() ); }
mell1008

2024/08/29 13:52

@AbeTakashi様 @fana様 返信が遅くなってしまい申し訳ございません 具体的な状況をお伝えしきれておらず申し訳ございません。 time関数を使用した場合、乱数の出力が1秒以内に何度も行われるとの記載をサイトで見かけ、 sleep関数で1秒間あけないと同値の乱数が繰り返し出力されてしまうとの理解をしておりました。 ご指摘いただいた通り、Windows環境ではインクルードできないライブラリを使用しておりました。 お二方からアドバイスいただいたraind関数に初期値を設定する以下の文を代入したところ、 乱数がランダムに出力されるようになりました。 std::random_device SeedSource; srand( SeedSource() ); 今後は、いただいたご指摘内容とアドバイスを活かしで学習を進めていきたいです。 ご回答ありがとうございます。
fana

2024/08/30 01:36 編集

> time関数を使用した場合、乱数の出力が1秒以内に何度も行われるとの記載をサイトで見かけ、 > sleep関数で1秒間あけないと同値の乱数が繰り返し出力されてしまうとの理解をしておりました。 まだ話の意味がわからないですが…… 乱数系列の初期化というのは,(ふつうは?)最初らへんで(例えばmain関数内の最初のあたりとかで)1回だけやれば良い :rand()で乱数値を得る度に行わねばならないという話ではない …っていうところに誤解(?)があったりするのか, それとも本当に前述したようなこと(このプログラムを怒涛の勢いで実行しまくると,1秒以内に起動させた複数のプログラムで結果が同じになる:例えば 0.1秒おきに100個起動させるとしたら,実行結果の種類が10~11種類しかないという状況になる)というのを問題視されているのか? 後者であれば,「各プログラムが 1秒sleep する」ことに意味は無く,「怒涛の勢いで実行する何からの手段の側を見直す:そんな勢いで大量に実行させても意味ないので1秒おきに実行することにするとか」という事を考えねば意味が無い気がします.
mell1008

2024/08/31 07:51

fana様 ご回答いただきありがとうございます。 記述いただいた後者の例を問題視して質問を挙げさせていただきました。 「そんな勢いで大量に実行させても意味ないので1秒おきに実行することにする」 ➡こちらを実現するためにsleep関数を使用しておりました。  ユーザが任意の数を入力する場合は入力するスピードをコントロールできると思うのですが、乱数など自動でプログラムが連続して出力する場合もスピードをコントロールできるのでしょうか? 理解が乏しく申し訳ございません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問