★基本制御文(While17)★
それでは、除算を減算で行うプログラムを考えてみましょう。
乗算は加算を繰り返すことで出来ました。
除算は減算を繰り返すことで出来ます。
13÷4を考えてみます。
13÷4の答えは「3.25」ですが、少数以下を考えると難しくなるので、「商と余り」という形で計算します。
13÷4の商は3、余りは1です。
これを減算を繰り返す方法で考えてみると、
13−4=9
9−4=5
5−4=1
この時点で1から4を減算するとマイナスになりますので、計算を止めます。
減算は3回行っています。
最後の計算の答えは1です。
これが商と余りになります。
最初はマイナス等は考慮しなくて構いませんので、考えてみてください。
<実行結果 VC++ Express Edition>
元の数を入力してください:13
割る数を入力してください:4
商は3、余りは1です。
続行するには何かキーを押してください・・・
解答例です。
<sample program 044-01>
#include <stdio.h>
void main()
{
int input1;
int input2;
int syou;
int amari;
printf( "元の数を入力してください:" );
scanf( "%d", &input1 );
printf( "割る数を入力してください:" );
scanf( "%d", &input2 );
syou = 0;
amari = input1;
while( amari >= input2 ) {
amari -= input2;
syou++;
}
printf( "商は%d、余りは%dです。\n", syou, amari );
}
|
<実行結果 VC++ Express Edition>
元の数を入力してください:13
割る数を入力してください:4
商は3、余りは1です。
続行するには何かキーを押してください・・・
商は減算した回数を数えれば良いですから、カウンタですね。
余りは元の数から減算を繰り返し、これ以上引くとマイナスになる、という数値です。
合計の逆で、変数「amri」に元の数「input1」を入れておいて、
amari -= input2;
で、どんどん減算していきます。
繰り返し条件は、
while( amari >= input2 )
となっていますので、
amariがinput2より小さくなったら、繰り返しを終了します。
※amariとinput2が同じ時は、まだ減算できます。
では、別の数値を入力してテストを行ってみましょう。
<実行結果 VC++ Express Edition>
元の数を入力してください:4
割る数を入力してください:5
商は0、余りは4です。
続行するには何かキーを押してください・・・
元の数より割る数を大きくしてみましたが、正しく結果が表示されました。
では「0」を使ってみましょう。
<実行結果 VC++ Express Edition>
元の数を入力してください:0
割る数を入力してください:5
商は0、余りは0です。
続行するには何かキーを押してください・・・
元の数を「0」にすると、正しく結果が出ています。
では、割る数に「0」を入れてみます。
<実行結果 VC++ Express Edition>
元の数を入力してください:5
割る数を入力してください:0
終わらなくなりました・・・
元の数から割る数を減算していきますが、「0」を減算していますから、いつまでたっても元の数が減らないのです。
では、応急処置を・・・と言いたい所ですが、「0」で割るというのは元々コンピュータでは出来ないのです。
下のプログラムを実行してみてください。
<sample program 044-02>
#include <stdio.h>
void main()
{
int data;
data = 10;
printf( "%d\n", data / 0 );
}
|
<実行結果 VC++ Express Edition>
エラーになりました。
よく見ると、コンパイルした時に警告(warning)が出ています。
warning C4723: 除算の2番目のオペランドは、コンパイル時に
0 と評価され、不定の結果を返します。
「除算の2番目のオペランド」とは、除算の右辺のことです。
なぜ、このような警告が出るのか説明します。
ゼロディバイド(ゼロ除算)
ゼロ除算については、以前に少し書きました。
1÷0.1の答えはいくつでしょう?
「10」ですね。
1÷0.01は?
「100」です。
1÷0.001は?
「1000」です。
このまま、右辺をず〜っとゼロに近づけていくと、答えはどんどん大きくなっていきます。
つまり、ゼロで割ると答えが無限大となってしまい、コンピュータでは計算出来ないのです。
では、除算のプログラムに戻って、ゼロ除算を回避するプログラムを考えてみましょう。
解答例です。
<sample program 044-03>
#include <stdio.h>
void main()
{
int input1;
int input2;
int syou;
int amari;
printf( "元の数を入力してください:" );
scanf( "%d", &input1 );
printf( "割る数を入力してください:" );
scanf( "%d", &input2 );
if( input2 != 0 ) {
syou = 0;
amari = input1;
while( amari >= input2 ) {
amari -= input2;
syou++;
}
printf( "商は%d、余りは%dです。\n", syou, amari );
}
else {
printf( "ゼロ除算エラー\n" );
}
}
|
<実行結果 VC++ Express Edition>
元の数を入力してください:5
割る数を入力してください:0
ゼロ除算エラー
続行するには何かキーを押してください・・・
割る数(input2)が「0」の場合、計算をせず「ゼロ除算エラー」と表示します。
では、マイナスへの対処を考えてみましょう。
乗算では、右辺がマイナスの場合を考えればよかったのですが、除算の場合両辺とも考慮する必要があります。
−8÷4
−8から4を減算するとマイナスが増加していきます。
8÷−4
8から−4を減算するとどんどん増えていきます。
−8÷−4
−8から−4を減算すると2回で0になると思いますが、実際には繰り返し条件が、
amari = input1;
while( amari >= input2 )
となっているため、最初から繰り返し条件が不成立となり、一度も繰り返されずに終了します。
色々と効率の良い方法はありそうですが、前回の乗算で使った「minus_flag」を利用して考えてみてください。
解答例です。
<sample program 044-04>
#include <stdio.h>
void main()
{
int input1;
int input2;
int syou;
int amari;
int left_minus_flag;
int right_minus_flag;
printf( "元の数を入力してください:" );
scanf( "%d", &input1 );
left_minus_flag = 0;
if( input1 < 0 ) {
left_minus_flag = 1;
input1 = -input1;
}
printf( "割る数を入力してください:" );
scanf( "%d", &input2 );
right_minus_flag = 0;
if( input2 < 0 ) {
right_minus_flag = 1;
input2 = -input2;
}
if( input2 != 0 ) {
syou = 0;
amari = input1;
while( amari >= input2 ) {
amari -= input2;
syou++;
}
if( left_minus_flag == 1 ) {
syou = -syou;
}
if( right_minus_flag == 1 ) {
syou = -syou;
}
printf( "商は%d、余りは%dです。\n", syou, amari );
}
else {
printf( "ゼロ除算エラー\n" );
}
} |
<実行結果1 VC++ Express Edition>
元の数を入力してください:-8
割る数を入力してください:4
商は-2、余りは0です。
続行するには何かキーを押してください・・・
<実行結果2 VC++ Express Edition>
元の数を入力してください:8
割る数を入力してください:-4
商は-2、余りは0です。
続行するには何かキーを押してください・・・
<実行結果3 VC++ Express Edition>
元の数を入力してください:-8
割る数を入力してください:-4
商は2、余りは0です。
続行するには何かキーを押してください・・・
右辺か左辺がマイナスの場合、商はマイナスになり、右辺も左辺もマイナスの場合、商はプラスになります。
では、次回は累乗(べき乗)を乗算の繰り返しで行うというプログラムを作ってみましょう。