はじめに
乱数は、プログラミングのさまざまなシーンで利用されます。
それはゲームの敵キャラクターの行動やデータ分析のシミュレーション、ユニークなIDの生成など、多岐にわたります。
C言語では、これらの乱数生成が可能で、その利用方法は非常に多様です。
本記事では、C言語を用いた乱数生成の手順とその活用例について、実際のコードを交えて解説していきます。
●C言語による乱数生成とは
乱数とは、その値が予測不能で、かつ生成前後の値が独立している数のことを指します。
C言語における乱数生成は、「rand()」関数を使用して行います。
○乱数の原理
C言語で乱数を生成する際の基本となるのが「rand()」関数と「srand()」関数です。
rand()関数は、0からRAND_MAX(通常は32767)までの間の整数型の乱数を返します。
srand()関数は、乱数生成の種(シード)を設定します。
乱数は厳密には「疑似乱数」であり、同じシードからは同じ乱数列が生成されます。
○乱数の活用例
乱数は、シミュレーションのランダムな挙動、IDの生成、データのシャッフルなど、様々なシーンで利用されます。
●C言語での乱数生成:具体的な手順
C言語での乱数生成は、シンプルですが、その活用方法は多様です。
それでは乱数生成の基本的な手法と応用例を紹介します。
○乱数の生成方法
乱数生成の基本は、srand()でシードを設定し、rand()で乱数を生成することです。
□サンプルコード1:基本的な乱数生成
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
srand(time(NULL)); // シードの設定
int num = rand(); // 乱数の生成
printf("%d\n", num); // 乱数の出力
return 0;
}
このコードでは、まず標準ライブラリと時間を取得するためのライブラリをインクルードします。
main関数内で、srand(time(NULL))を使って乱数のシードを設定しています。
これにより、現在の時間(エポック秒)をシードとして利用しています。
次にrand関数を用いて乱数を生成し、生成した乱数を出力しています。
□サンプルコード2:範囲指定による乱数生成
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
srand(time(NULL)); // シードの設定
int num = rand() % 100; // 0〜99の乱数の生成
printf("%d\n", num); // 乱数の出力
return 0;
}
このコードでは、rand()関数で生成した乱数に対して「%」演算子を用いて100で割った余りを計算し、0から99までの乱数を生成しています。
このように、範囲指定した乱数を生成することも可能です。
○乱数の使い方
次に、乱数の応用例として、配列のシャッフルとシミュレーションの例を見ていきましょう。
□サンプルコード3:乱数を使った配列のシャッフル
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define N 10 // 配列の要素数
void swap(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
int main() {
srand(time(NULL)); // シードの設定
int array[N];
for (int i = 0; i < N; i++) { // 配列の初期化
array[i] = i;
}
for (int i = 0; i < N; i++) { // 配列のシャッフル
int j = rand() % N;
swap(&array[i], &array[j]);
}
for (int i = 0; i < N; i++) { // シャッフル後の配列の出力
printf("%d ", array[i]);
}
printf("\n");
return 0;
}
このコードでは、swap関数を定義して、配列の要素の交換を行っています。
main関数内では、まず乱数のシードを設定し、配列を初期化しています。
その後、乱数を使って配列のシャッフルを行い、結果を出力しています。
配列のシャッフルは、乱数を使った一例としてよく用いられます。
□サンプルコード4:乱数を使ったシミュレーション
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define TRIALS 10000 // 試行回数
int main() {
srand(time(NULL)); // シードの設定
int heads = 0; // 表の回数
for (int i = 0; i < TRIALS; i
++) {
if (rand() % 2 == 0) { // 0または1の乱数の生成
heads++;
}
}
printf("Heads: %d, Tails: %d\n", heads, TRIALS - heads); // 結果の出力
return 0;
}
このコードでは、コイン投げのシミュレーションを行っています。
コード内でrand()関数を使って0または1の乱数を生成し、その結果を用いて表か裏かを判定しています。
乱数は、このような確率的なシミュレーションで頻繁に用いられます。
●注意点と対策
C言語における乱数生成には、いくつか注意点があります。
それでは、その一部を取り上げ、対策を紹介します。
○偏りのある乱数
「rand() % n」で乱数を生成すると、一部の値が出やすい傾向があります。
この問題を確認するためのコードを紹介します。
□サンプルコード5:乱数の偏りを確認する
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define TRIALS 100000 // 試行回数
#define N 20 // 乱数の範囲
int main() {
srand(time(NULL)); // シードの設定
int count[N] = {0}; // カウントの初期化
for (int i = 0; i < TRIALS; i++) {
int num = rand() % N; // 0〜N-1の乱数の生成
count[num]++;
}
for (int i = 0; i < N; i++) { // カウントの出力
printf("%d: %d\n", i, count[i]);
}
return 0;
}
このコードでは、乱数の偏りを確認するために、大量の乱数を生成し、各値が何回出現したかをカウントしています。
これにより、乱数の出現分布を確認することができます。
○乱数の再現性
乱数は同じシードから同じ列を生成するため、再現性があります。
これを利用したコードを紹介します。
□サンプルコード6:同じ乱数列を再現する
#include <stdio.h>
#include <stdlib.h>
#define N 5 // 出力する乱数の個数
int main() {
srand(12345); // シードの設定
for (int i = 0; i < N; i++) { // 乱数の出力
printf("%d ", rand());
}
printf("\n");
return 0;
}
このコードでは、特定の値(ここでは12345)をシードとして設定しています。
これにより、同じ乱数列を再現することができます。
●乱数生成のカスタマイズ
C言語での乱数生成は、カスタマイズ可能です。
より良い乱数を生成する方法を紹介します。
○より良い乱数の生成
「rand()」関数は疑似乱数生成器であり、その品質は必ずしも高くありません。
より良い乱数を生成するためには、より高品質な乱数生成アルゴリズムを実装するか、それを提供するライブラリを使用する方法があります。
□サンプルコード7:より良い乱数の生成方法
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
srand(time(NULL)); // シードの設定
int num = rand() / ((double) RAND_MAX + 1) * 100; // 0〜99の乱数の生成
printf("%d\n", num); // 乱数の出力
return 0;
}
このコードでは、rand()関数の結果をRAND_MAX + 1で割り、その結果に100を掛けることで0から99までの乱数を生成しています。
これにより、範囲指定した乱数を生成する際の偏りを緩和することができます。
まとめ
C言語での乱数生成は、多くのプログラムにおいて重要な要素です。
基本的な乱数生成から応用、そして注意点やカスタマイズ方法まで、本記事を通じて理解を深めることができましたら幸いです。
プログラミングにおける乱数の活用は、ぜひ自身のコードに取り入れてみてください。