閉じる

【C言語】randで0からRAND_MAXの乱数を作る基本と注意点

C言語で乱数を得る最初の一歩は、標準ライブラリ<stdlib.h>のrand()を理解することです。

randは0からRAND_MAXまでの整数を返す擬似乱数生成器で、初心者の方はこの「範囲」と「使い方」を丁寧に押さえることが大切です。

この記事では、単発と複数回の生成、printf()での確認、環境ごとの違い、そして使う際の注意点を順序立てて解説します。

randの基本

rand()は0〜RAND_MAXの整数を返す

rand()標準ライブラリ<stdlib.h>に含まれる関数で、呼び出すたびに0以上かつRAND_MAX以下の整数を返します。

戻り値の型はintです。

C言語標準では分布の性質には強い保証はありませんが、一般的な実装では一様分布に近い擬似乱数が生成されます。

関数プロトタイプは次のとおりです。

int rand(void);

範囲の端(0とRAND_MAX)も含まれることを覚えておくと、境界条件のテストに役立ちます。

RAND_MAXの意味

RAND_MAXマクロ定数で、rand()が返し得る最大値を表します。

定義場所は<stdlib.h>で、少なくとも32767であることが標準で保証されています。

ただし実際の値は処理系に依存し、より大きい場合があります。

つまり「何ビットの乱数が得られるか」は環境次第です。

randの使い方

乱数を1回生成する

基本形は「必要に応じて1回rand()を呼び、intで受け取る」というものです。

実運用では毎回同じ並びを避けるため、プログラム開始時に1度だけsrand()で乱数の種(シード)を与えるのが通例です(シードの詳細は別記事で扱います)。

C言語
#include <stdio.h>
#include <stdlib.h>  // rand, srand, RAND_MAX
#include <time.h>    // time

int main(void) {
    // 実行ごとに異なる系列にするためのシード設定(詳細は別記事)
    srand((unsigned)time(NULL));

    // 0〜RAND_MAXの乱数を1回生成
    int r = rand();

    // 値を表示
    printf("生成された乱数: %d\n", r);
    return 0;
}

出力例(一例):

生成された乱数: 1804289383

上記の数字は実行環境により変わります。

ループで複数回生成

複数の乱数が必要なときは、シード設定は最初の1回だけにして、その後はrand()をループで呼び出します。

C言語
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void) {
    srand((unsigned)time(NULL));  // シードは1回だけ

    // 10個の乱数を生成して表示
    for (int i = 0; i < 10; ++i) {
        int r = rand();  // 0〜RAND_MAX
        printf("%2d回目: %d\n", i + 1, r);
    }
    return 0;
}

出力例(一例):

 1回目: 1103527590
 2回目: 377401575
 3回目: 894259142
 4回目: 960570631
 5回目: 1804289383
 6回目: 846930886
 7回目: 1681692777
 8回目: 1714636915
 9回目: 1957747793
10回目: 424238335

実行ごとに値が変化していれば、シード設定と乱数生成が適切に動いています。

printf()で値を確認

rand()の戻り値はintです。

表示には%d指定子を使うのが基本です。

余計なトラブルを避けるため、型とフォーマット指定子の組み合わせは常に一致させましょう。

C言語
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    // シードは省略(注意点の節で解説)
    int r = rand();  // intで受け取る

    // %dはintに対応する指定子
    printf("rand()の値(int, %%d): %d\n", r);

    // 幅や整形も可能(右寄せで10桁)
    printf("整形表示(幅10): %10d\n", r);

    return 0;
}

出力例(一例):

rand()の値(int, %d): 41
整形表示(幅10):         41

改行\nを付けると、出力がバッファリングされずに見やすくなります。

RAND_MAXの確認とポイント

値は環境によって違う

RAND_MAXは処理系依存です。

以下は代表的な環境の一例です。

実際には各自の環境で確認してください。

環境の例RAND_MAXの値備考
Windows(MSVC)3276715ビット相当
Linux(glibc)214748364731ビット相当
macOS(Clang, libSystem)214748364731ビット相当
MinGW(MSVCRT系)3276715ビット相当

この違いにより、得られる乱数の「粗さ」や上限が環境で変わります。

0と最大値も出る

rand()の範囲は0以上かつRAND_MAX以下で「両端を含む」ため、理屈の上では0RAND_MAXも出現し得ます。

いずれも確率は約1 / (RAND_MAX + 1)です。

境界値を前提にしたテストではこの点を意識しておくと安全です。

実行してRAND_MAXを表示

自分の環境のRAND_MAXを知るには、実際に表示させるのが確実です。

C言語
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void) {
    printf("この環境のRAND_MAX: %d\n", RAND_MAX);

    srand((unsigned)time(NULL));   // 実行ごとに系列を変える
    printf("サンプル乱数(1): %d\n", rand());
    printf("サンプル乱数(2): %d\n", rand());
    return 0;
}

出力例(一例):

この環境のRAND_MAX: 2147483647
サンプル乱数(1): 1609348863
サンプル乱数(2): 1481765933

数値は環境により異なるので、同じ結果にならなくても問題ありません。

randの注意点

シード未設定は毎回同じ結果

シード(srand())を設定しないと、実行のたびに同じ並びの値が得られます。

テストには便利ですが、実運用での乱数らしさは失われます。

C言語
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    // srand(...) を呼ばない例
    for (int i = 0; i < 5; ++i) {
        printf("%d ", rand());
    }
    printf("\n");
    return 0;
}

出力例(1回目):

41 18467 6334 26500 19169

出力例(2回目):

41 18467 6334 26500 19169

2回とも同じ並びになっていることが分かります。

実行ごとに変えたい場合は、プログラム開始時にsrand((unsigned)time(NULL))などでシードを与えましょう(理由や選び方は別記事で解説します)。

int型の値として扱う

rand()の戻り値はintです。

代入や表示ではintを前提に扱います。

  • 代入例: int r = rand();
  • 表示例: printf("%d\n", r);

フォーマット指定子を間違えると未定義動作の原因になります。

特に%ld%uなど他型の指定子を流用しないように注意してください。

なおrand()暗号用途には不適です。

セキュアな乱数が必要な場合は別のAPIを検討します。

範囲の変更は別記事で解説

0〜RAND_MAXのままでは使いにくい場面も多く、例えば1〜100などの範囲に変換したくなります。

よくある書き方はrand() % 100 + 1ですが、分母(RAND_MAX + 1)が範囲で割り切れないと偏りが生じる可能性があります。

正しい範囲変換の方法や偏りの話題は別記事で丁寧に解説します。

本記事では「まずは0〜RAND_MAXの整数を安全に受け取り、理解する」ことに集中しましょう。

まとめ

rand()は0〜RAND_MAXの整数を返す基本の乱数生成関数で、RAND_MAXは処理系依存の上限値です。

初心者の方は、(1) <stdlib.h>をインクルードし、(2) 必要ならsrand()でシードを1度だけ設定し、(3) intで受けて%dで表示する、という手順を確実に身につけてください。

境界値(0と最大値)も出得ること、RAND_MAXが環境で異なることを確認し、用途に応じて正しい範囲変換やシードの扱いへと理解を広げていきましょう。

C言語 標準ライブラリの活用

この記事を書いた人
エーテリア編集部
エーテリア編集部

プログラミングの基礎をしっかり学びたい方向けに、C言語の基本文法から解説しています。ポインタやメモリ管理も少しずつ理解できるよう工夫しています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!