例えばパスワードなどでは乱数を使って無作為に英文字や数値を選んで並べたものが使われています。
この記事では、乱数について
- 乱数とは
- randの使い方
- randを使ったサンプルコード
など基本的な内容から、具体的な使い方の内容についても解説していきます。今回は乱数について、使い方をわかりやすく解説します!
乱数とは
乱数とは一意的ではなくランダムで何が出るかわからない数字のことです。C言語ではrand関数を使ってよく疑似乱数を生成させます。プログラミングで生成する乱数の羅列はそれぞれの値はランダムで生成されますが、同じ羅列を再現して出すことができるので何が出るか先読みすることができます。したがって本当の意味での乱数ではないので、区別して疑似乱数と呼んでいます。
【なかなかエラーが解決できない…そんな悩みを解決します!】
登録無料で始められるプログラミングスクール「侍テラコヤ」
・回答率100%のQ&A掲示板でエラーを解決!
・現役エンジニアとのオンライン相談で悩みを解決!
・50種類以上の教材で複数言語を習得!
randの使い方
rand関数を使って乱数を発生させる方法についてみていきましょう。
基本的な使い方
rand関数を使うためにはヘッダーファイル「stdlib.h」をインクルードする必要があります。rand関数を使うと0~RAND_MAXまでの整数の乱数を生成することができます。RAND_MAXはヘッダーファイル「stdlib.h」で定義されています。
RAND_MAXの値は環境により異なりますので注意しましょう。この解説では下記のように定義されている環境で確認しています。
#define RAND_MAX 0x7fffffff
0x7fffffffは十進数で表すと2147483647となります。
したがって0~2147483647までの乱数を発生させることになります。rand関数は引数は指定しません。
それではサンプルコードで使い方をみていきましょう。
#include <stdio.h> #include <stdlib.h> int main(void) { printf("RAND_MAX: %d\n", RAND_MAX); // 0から2147483647までの乱数を発生 for(int i = 0; i < 3; i++) { printf("%d\n", rand()); } // 1から10までの乱数を発生 for(int i = 0; i < 3; i++) { printf("%d\n", rand() % 10 + 1); } return 0; }
実行結果:
RAND_MAX: 2147483647 1804289383 846930886 1681692777 6 4 6
このサンプルコードでは3回繰り返して乱数を発生させています。乱数を発生させていますので、環境を変えて実行した結果はこの結果とは異なる表示になります。
この環境ではrand関数は0から2147483647までの乱数を生成しますので、例えば1~10までの乱数を生成したい場合は10の剰余に1加えて1~10の数値を算出します。なお、このサンプルコードでは繰り返し実行しても同じ結果が繰り返し出力表示されますので注意しましょう。実行するたびに違う結果を出力表示したい場合はrand関数を使う前に初期化を行う必要があります。
初期化の方法について詳しくみていきましょう!
初期化の方法
初期化を行うにはsrand関数を使用します。
srand関数の引数には符号なし整数を使用します。符号なし整数に同じ値を使うと乱数は同じ値で初期化されます。乱数の初期値を毎回変えたい場合は、一般にtime関数を使って現在の時刻を取得して利用します。
time関数は現在の歴時刻を秒単位で取得します。ちなみに歴時刻とはグリニッジ標準時の1970年1月1日0時から現在までの経過時間を秒単位で表したものです。time関数を使うためにはヘッダーファイル「time.h」をインクルードする必要があります。time関数の引数にNULLを指定して使用します。
それではサンプルコードで確認していきましょう。
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <unistd.h> int main(void) { for(int i = 0; i < 3; i++) { srand(1); // 乱数の初期化 printf("%d回目の乱数発生: ", i + 1); // 0から2147483647までの乱数を発生 for(int j = 0; j < 3; j++) { printf("%d, ", rand()); } printf("\n"); } for(int i = 0; i < 3; i++) { srand((unsigned int)time(NULL)); // 現在時刻の情報で初期化 printf("%d回目の乱数発生: ", i + 1); // 0から2147483647までの乱数を発生 for(int j = 0; j < 3; j++) { printf("%d, ", rand()); } sleep(1); // time関数で取得する時刻を変えるために1秒待機 printf("\n"); } for(int i = 0; i < 3; i++) { srand((unsigned int)time(NULL)); // 現在時刻の情報で初期化 printf("%d回目の乱数発生: ", i + 1); // 1から10までの乱数を発生 for(int j = 0; j < 3; j++) { printf("%d, ", rand() % 10 + 1); } sleep(1); // time関数で取得する時刻を変えるために1秒待機 printf("\n"); } return 0; }
実行結果:
1回目の乱数発生: 1804289383, 846930886, 1681692777, 2回目の乱数発生: 1804289383, 846930886, 1681692777, 3回目の乱数発生: 1804289383, 846930886, 1681692777, 1回目の乱数発生: 1004092231, 3888874, 662954966, 2回目の乱数発生: 1779225463, 899014191, 250342318, 3回目の乱数発生: 1467717538, 1774429879, 1966374531, 1回目の乱数発生: 5, 8, 7, 2回目の乱数発生: 3, 8, 7, 3回目の乱数発生: 9, 9, 7,
このサンプルコードでは、srand関数を使ってrand関数を初期化しています。まずsrand関数の引数に1を指定して初期化しrand関数で乱数を発生させた場合は、3回とも同じ乱数が生成されています。次にsrand関数の引数にtime関数を使って初期化しrand関数で乱数を発生させた場合は、3回とも違う値の乱数が生成されています。
なお、time関数は秒単位で歴時刻を取得しますので繰り返し処理が1秒以内で終了する場合は同じ歴時刻を取得します。
そうすると同じ値で初期化することになりますので、このサンプルコードではsleep関数を使って1秒待機させ違う歴時刻を取得するようにしています。sleep関数を使うにはヘッダーファイル「unistd.h」をインクルードする必要があります。
randを使ったサンプルコード
rand関数を使って乱数を生成するサンプルコードとして、サイコロの出目を表示する例とじゃんけんの勝ち負けを表示する例をご紹介します。
サイコロ
このサンプルコードではrand関数を使って1~6までの乱数を生成し出力表示しています。
srand関数を使って現在の歴時刻で初期化していますので、実行するたびに出力表示は変わります。
#include <stdio.h> #include <stdlib.h> #include <time.h> int main(void) { srand((unsigned int)time(NULL)); // 現在時刻の情報で初期化 for(int i = 0; i < 3; i++) { printf("%d回目: ", i + 1); // 1から6までの乱数を発生 int num = rand() % 6 + 1; switch(num) { case 1: printf("一の目が出ました\n"); break; case 2: printf("二の目が出ました\n"); break; case 3: printf("三の目が出ました\n"); break; case 4: printf("四の目が出ました\n"); break; case 5: printf("五の目が出ました\n"); break; case 6: printf("六の目が出ました\n"); break; default: printf("numの値が不正です\n"); } } return 0; }
実行結果:
1回目: 四の目が出ました 2回目: 二の目が出ました 3回目: 三の目が出ました
じゃんけん
このサンプルコードではrand関数を使って0~2までの乱数を生成しています。0の場合はグー、1の場合はチョキ、2の場合はパーとしてじゃんけんの勝ち負けの出力表示処理をしています。
こちらもsrand関数を使って現在の歴時刻で初期化していますので、実行するたびに出力表示は変わります。
#include <stdio.h> #include <stdlib.h> #include <time.h> int main(void) { srand((unsigned int)time(NULL)); // 現在時刻の情報で初期化 for(int i = 0; i < 3; i++) { printf("%d回目: ", i + 1); // 0から2までの乱数を発生 int num1 = rand() % 3; int num2 = rand() % 3; if(num1 == num2) { if(num1 == 0) { printf("Aはグーで、Bもグー。引き分け。\n"); } else if(num1 == 1) { printf("Aはチョキで、Bもチョキ。引き分け。\n"); } else { printf("Aはパーで、Bもパー。引き分け。\n"); } } else if(num1 == 0) { if(num2 == 1) { printf("Aはグーで、Bはチョキ。Aの勝ち。\n"); } else { printf("Aはグーで、Bはパー。Bの勝ち。\n"); } } else if(num1 == 1) { if(num2 == 0) { printf("Aはチョキで、Bはグー。Bの勝ち。\n"); } else { printf("Aはチョキで、Bはパー。Aの勝ち。\n"); } } else if(num1 == 2) { if(num2 == 0) { printf("Aはパーで、Bはグー。Aの勝ち。\n"); } else { printf("Aはパーで、Bはチョキ。Bの勝ち。\n"); } } } return 0; }
実行結果:
1回目: Aはパーで、Bもパー。引き分け。 2回目: Aはグーで、Bはチョキ。Aの勝ち。 3回目: Aはグーで、Bはパー。Bの勝ち
【何から学べばいいかわからない…そんな悩みを解決します!】
完全無料ですぐわかる「プログラミング学習プラン診断」
・適性にあわせて学習プランを診断
・完全無料で気軽に診断できる
・学習の悩みもまるっと解決
まとめ
ここでは、乱数の生成について説明しました。
rand関数を使って乱数を生成する場合、実行するたびに同じ値の乱数を生成させるか、毎回繰り返し同じ値で初期化して同じ値の乱数を生成させるか、毎回違う値で初期化して違う値の乱数を生成させるか目的にあわせて乱数の生成方法を選ぶ必要があります。
目的にあわせて使い分けることができるように、この記事を何度も参考にして下さいね!