割り算の余り

ホームC#入門講座第2章:疑似サイコロ > 割り算の余り

割り算の余り

割ってみる

さて問題です。あらかじめ言っておきますが、答えはこのページのタイトルです。ただし、少しだけ注意してください。

(例題)

ここに A | B | C | D | E | F の箱が1つずつ、合計6個ある。
これらの箱に1から30までの整数 n を入れていく場合、
どのような基準で入れればすべての箱の中の数の個数が等しくなるか。

答えはもちろん、割った余りを使うのです。

(解)

n を 6 で割った余りで分類するのが妥当である。
すなわち、
A = 6で割って1余る数 ( 1,7,13,19,25 )
B = 6で割って2余る数 ( 2,8,14,20,26 )
C = 6で割って3余る数 ( 3,9,15,21,27 )
D = 6で割って4余る数 ( 4,10,16,22,28 )
E = 6で割って5余る数 ( 5,11,17,23,29 )
F = 6で割って0余る数(割り切れる数) ( 6,12,18,24,30 )
とすれば、すべての箱に6個ずつ入る。

サイコロの目

さて、上で注意が必要と言ったのは、この基準をサイコロに見立てる場合です。サイコロの目は「1から6まで」であり、0は含まれません。よって、「余りが0の時は6であると見たてる」という処理が必要になります。

このような考え方に基づいて、「ユーザーに整数を入力してもらい、その数を6で割った余りをサイコロの目として表示する。ただし、余りが0になった場合はサイコロの目は6であるとする」という機能を持ったプログラムを作ります。

ここで新しい項目が2つ登場しました。一つは「余り」で、もう一つは「ただし」です。ではまず、「余り」をどのようにして求めるかを考えてみましょう。

余りを求めるアルゴリズム

実は余りを求める機能はC#にはもともと備わっているので、あえてそのアルゴリズムを考える必要はありません。ですが、ここではあえてプログラマらしく、アルゴリズムを考えてみます。

(例題)

ある整数 x, y が与えられたとき、x を y で割った余りを求めるにはどうすればいいか。

ここで必要になるのが、「型」の正確な理解です。次のプログラムを理解することができますか? 新しい概念は一切用いていません。

using System;
namespace NewWorld
{
	class MainClass
	{
		public static void Main(string[] args)
		{
			int x = 10;
			int y = 3;
			int z = x / y;
			Console.WriteLine("{0} ÷ {1} = {2} ・・・ {3}", x , y , z ,  x - (y * z));
		}
	}
}

最大のポイントは、x = 10, y = 3 という条件の元では、z に何が入るか、です。

通常の考えでは「10÷3=3.333333・・・」ですから、3.33333が入ることになります。しかし、ここではint型として変数zが宣言されています。よって、zは必ず整数であり、小数点以下は自動的に切り捨てられます。よって、z = 3です。

試しに、xもyもzも全部 double にして計算してみてください。結果が変わります。

このように、余りを計算するアルゴリズムは完成しました。C#ではこの機能はもともと備わっています。

Console.WriteLine("10 ÷ 3 = 3 ・・・ {0}", 10 % 3);

「%」は割った余りを示す「剰余演算子」です。また、以前に紹介した「Mathクラス」を利用することもできます。

Console.WriteLine("10 ÷ 3 = 3 ・・・ {0}", Math.IEEERemainder(10, 3));

この「MathクラスのIEEERemainderメソッド」を使えば、0で割った場合もプログラムが暴走することはありません。NaNという0で割ったときの特別な値が出力されます。

いきなりソースコード

説明が長くなってきたので、もうソースコードをお見せいたしましょう。

using System;
namespace NewWorld
{
	class MainClass
	{
		public static void Main(string[] args)
		{
			Console.Write("整数を入力してください。>");
			int x = int.Parse(Console.ReadLine());
			
			int y = x % 6;
			if (y == 0)
				y = 6;
			
			Console.WriteLine("{0}から出力されたサイコロの目は {1} です。", x , y );
		}
	}
}

新しく習うのは一箇所だけです。

if (y == 0)
    y = 6;

これは誰が見ても直感的に理解できるように、「yが0に等しければ、yに6を代入しろ」という意味です。これをif構文といい、条件分岐の構文です。全く難しくありません。

このif構文を拡張して else if や else も登場することがあります。それらはまた登場するときに軽く見ればいいでしょう。if構文はいずれにしても直感的なので、とまどう必要はありません。ただ、「==」のように、イコールがふたつの「等号演算子」を利用することだけ覚えていてください。

時間と組み合わせて

上のプログラムではユーザの入力が必要ですが、自動でサイコロをふることも可能です。原理は一緒ですが、数値をユーザから得るのではなく、時刻から得るのです。

DateTime dt = DateTime.Now;
int x = dt.Millisecond;
			
int y = x % 6;
if (y == 0)
    y = 6;
			
Console.WriteLine("サイコロの目は {1} です。", x , y );

Millisecondはミリ秒といわれる単位で、1秒の1000分の1です。この数値を元にサイコロを振っています。理論的には正確な値が出るはずです。ですが、私が6回自分で実行したら、5が3回も出て、4と6が1回もでませんでした。

繰り返しを学んだら、このプログラムを1000回ほど実行して、統計をとってみたいと思います。