【C言語】任意の範囲内で”nの倍数”を乱数生成する方法【番外編】

C言語

ようこそ、KiRiOのブログへ!

本記事では「新・明解C言語中級編」の自由課題について解説します。


自由課題のとおり、この参考書には解答が載っておりません。
そこで、本記事で私なりの解答を共有しますので、ぜひ解答の参考にしてみてください。

今回は、「演習1-4」の番外編となります。

ちなみに、課題内容は以下のとおりでした。

演習1-4当てさせる数を3以上999以下の3の倍数(3, 6, 9, …, 999)とした《数当てゲーム》を作成せよ。
3の倍数でない値が入力された場合に、ただちにゲームを終了するものと、比較結果を表示せず再入力させる(入力回数としてカウントしない)ものの二つを作ること。
プレーヤが入力できる最大の回数が、どのくらいであれば適当であるのかも考察すること。

詳細は下記ブログをご覧ください▼

【C言語】乱数で"3の倍数"を生成する際は”一般項”を用いよ
ようこそ、KiRiOのブログへ! 本記事では「新・明解C言語中級編」の自由課題について解説します。 自由課題のとおり、この参考書には解答が載っておりません。 そこで、本記事で私なりの解答を共有しますので、ぜひ解答の参考にしてみ...

「演習1-4」の解説ブログでは、3以上999以下の3の倍数(3, 6, 9, …, 999)を乱数として生成するために以下の手順で実装してまいりました。

  1. 乱数群を一般項を用いて表す
    • $3n$ ($n = 1, 2, 3, …, 333$)

  2. 一般項の$n$にあたる乱数を生成(1, 2, 3, …, 333)
    • 1 + rand() % (999 / 3)

  3. 生成した乱数を$n$倍する(3, 6, 9, …, 999)
    • 3 * (1 + rand() % (999 / 3))

「演習1-4」はこの方法で実装可能ですが、以下のような場合はどうでしょうか。

演習1-4(番外編)当てさせる数を4以上999以下の3の倍数(6, 9, 12, …, 999)とした《数当てゲーム》を作成せよ。
3の倍数でない値が入力された場合に、ただちにゲームを終了するものと、比較結果を表示せず再入力させる(入力回数としてカウントしない)ものの二つを作ること。
プレーヤが入力できる最大の回数が、どのくらいであれば適当であるのかも考察すること。


この課題に対して「演習1-4」の解説内容を適用させます。

  1. 乱数群を一般項を用いて表す
    • $3n + 3$ ($n = 1, 2, 3, …, 332$)

  2. 一般項の$n$にあたる乱数を生成(1, 2, 3, …, 332)
    • 1 + rand() % 332

  3. 生成した乱数を$n$倍する(3, 6, 9, …, 999)
    • 3 * (1 + rand() % 332)

結果として、生成乱数は「3, 6, 9, …, 996」となり「999」が含まれなくなってしまいます
また、「332」という数値も課題内容の値を使用していないため導出過程が不明瞭です

これらの問題を解決するために、rand()を用いた式を発展(一般化)させる必要があります。
「演習1-4」の解説内容を一般化できますと、指定範囲によらない倍数の乱数生成が可能となりますので、一緒に考えていきましょう。

設計

今回、一般化するために注目する部分は「生成乱数の最小値」にあたる「1」の部分です。

3 * (1 + rand() % (999 / 3))

まずは、指定範囲の最小値が変わることによって、最小値がどのように変動するのかを見てみましょう。

指定範囲の最小値 1 2 3 4 5 6 7 8 9
生成乱数の最小値 1 2 3

ご覧の通りです。この表だけですと、関係式が導出できそうでできません。
それでは、上表に「指定範囲の最小値を3で割ったときの商」を追記してみましょう。

「↓ ÷ 3」の商 0 1 2 3
指定範囲の最小値 1 2 3 4 5 6 7 8 9
生成乱数の最小値 1 2 3

上表より、生成乱数の最小値(3行目)を2列右に移動させると、商(1行目)と一致することがわかります。
したがって、指定範囲の最小値(2行目)を $a$ とすると、商は $a / 3$ となりますが、生成乱数の最小値は $(a + 2) / 3$ と表されます。
もう少し正確に表すと、「2」という数字は、割る数「3」から1を引いた値ですので $(a + (3 – 1)) / 3$ となります。
設計は以上となります。

実装

それでは、設計内容をもとに実装していきます。
設計部分の時点でほとんど完成していますが、今回の課題に置き換えますと指定範囲の最小値は「4」です。
そのため、“4〜999″の”3の倍数”を乱数で生成するためには以下のように表します。

3 * ((4 + (3 - 1)) / 3) + rand() % (999 / 3))

以上を実装したものが下記プログラムです(関連部分のみ記述)。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void)
{
	int try;
	int ans;

	do
	{
		printf("《数当てゲーム》を開始しますか?【はい…1/いいえ…0】:");
		scanf("%d", &try);

		if (try == 0)
		{
			return 0;
		}
	} while (try != 0 && try != 1);

	srand(time(NULL));
	ans = 3 * ((4 + (3 - 1) / 3) + rand() % (999 / 3));

	return 0;
}

以上で完了となります。
プログラムを実行して、3の倍数を答えとした《数当てゲーム》として機能しているか確認してみてください。

これで、指定範囲に対して、以下のように式を一般化することができました。

    a 以上 b 以下で3の倍数を乱数生成

    3 * ((a + (3 - 1) / 3) + rand() % (b / 3))

それでは、最後に倍数に対しても一般化してみましょう。
すでに予想できているかと思いますが、「3」の部分を自然数 $n$ を用いて一般化します。

    a 以上 b 以下で n の倍数を乱数生成

    n * ((a + (n - 1) / n) + rand() % (b / n))

まとめ

それでは、本記事で説明した内容を以下にまとめます。

    a 以上 b 以下で n の倍数を乱数生成

    n * ((a + (n - 1) / n) + rand() % (b / n))

ここまで、記事を読んでいただき、ありがとうございました。

最後に、今回取り上げた課題が記載されている本を紹介します。
今回扱った課題以外にも、様々なプログラム開発について記載されているため、この記事とあわせて読んでいただくと、より理解が深まると思います。


また、参考として以下の本もご紹介しておきます。

こちらもオススメです。2021年12月14日に最新版が発売されました!

それでは、また別の記事でお会いしましょう!

コメント

タイトルとURLをコピーしました