forは基本的に繰り返しの回数が分かっている時に使います。これに対して、何回やればよいかが分かっていないとき while を使います。
基本形です
初期の条件はwhileの前にやっておく while (繰り返す条件){ 繰り返す内容(いくつかの文) (繰り返す内容で条件が変化するように条件を選ぶ) }
具体例です。i= から sum が 1000 を越えるまで iを増やしながら繰り返します。
int sum = 0; int i = 0; while ( 1000 > sum ){ i = i + 1; sum =sum + i; } printf ("%d まで足すと合計が 1000 を越え %d になります\n",i,sum );
「繰り返す内容」に条件の変化がないと無限に繰り返すプログラムになってしまいます。
その時には [Ctrl]+[C] つまりコントロールキーを押しながらCを押します。
これはCancel(中止)をコンピュータに知らせるものです。
1: /* whileを使って繰り返し k0601.c */ 1: 2: #include <stdio.h> 3: 4: int main() 5: { 6: int max = 5000; 7: int sum = 0; 8: int i = 0; 9: while ( max > sum ){ 10: i = i + 1; 11: sum =sum + i; 12: } 13: printf ("%d まで足すと合計が %d を越え %d になります\n",i,max,sum ); 14: return 0 15: }
while ( max > sum ){
i=i+1
sum = sum + i
実行結果はこうなります。
~/c$ ./k0601 100 まで足すと合計が 5000 を越え 5050 になります
10進数の0.1を二進数に書きなおすと循環小数になります。ちょうど1/3が0.33333...となるようなものです。コンピュータはこれを有限の桁で表現しますから誤差が出ます。0.1を何回も足し算せばこの誤差が大きく目立ってくるはずです。これを調べてみます。
1: /* 誤差を確かめる k0602.c */ 2: #include <stdio.h> 3: 4: int main() 5: { 6: float x = 0.1; 7: float sum = 0; 8: int i = 0; 9: while ( (x > x*i-sum) && (x > sum-x*i) ){ 10: i=i+1; 11: sum =sum + x; 12: printf ("%d %f %f\n",i,x*i,sum ); 13: } 14: printf ("%f を %d 回足すと合計が\n",x,i); 15: printf ("%f のはずが\n",x*i); 16: printf ("%f になります\n",sum ); 17: printf ("%f だけ違います\n",x*i-sum ); 18: return 0; 19: }
float x = 0.1;
float sum = 0;
int i = 0;
x*i
とsum
の差が大きくなってxの程度になったところで計算を終わらせたいのですが、どちらが大きいか分かりませんので、順序を変えて引き、どちらかがxより大きくなったら終わりにします。 && は「かつ」で前後の比較式が両方共「真」になったときに「真」になります。真である限り続けるのがwhileですから、どちらかがxより大きくなったら終わりになります。&&
と >
の間にも +
と *
の間にあったような優先順位があり、この例では ( ) は不要ですが、見間違えないように書くことをおすすめします。実行結果は次のとおり。
~/c$ ./k0602 ....(略).... 10114 1011.400024 1011.300110 10115 1011.500000 1011.400085 10116 1011.600037 1011.500061 10117 1011.700012 1011.600037 10118 1011.799988 1011.700012 10119 1011.900024 1011.799988 0.100000 を 10119 回足すと合計が 1011.900024 のはずが 1011.799988 になります 0.100037 だけ違います
別のコンピュータでは答えがちょっと違います。右の0.1を加えていく計算は同じ様ですが、掛け算で誤差の累積しないより正確な値を出そうとしているところが異なります。ここはfloatとintと異なる型の変数の計算で、しかもintは32ビットOSと64ビットOSでは使用バイト数が異なることがありますからそれが影響しているのかもしれません。
~/c$ ./k0602 ....(略).... 10114 1011.400015 1011.300110 10115 1011.500015 1011.400085 10116 1011.600015 1011.500061 10117 1011.700015 1011.600037 10118 1011.800015 1011.700012 0.100000 を 10118 回足すと合計が 1011.800015 のはずが 1011.700012 になります 0.100003 だけ違います
floatは4バイトで2進数で精度(計算の細かさ)は23+1で24ビットです。十進表現での精度に直すと6~7桁の精度ですから、1011.800から下の値は信用できないのです。詳しいことは小数の表現(詳)を参照してください。
k0602.cに比べて色のついた部分が異なっています。
1: /* doubleの誤差を確かめる k0603.c */ 2: #include <stdio.h> 3: 4: int main() 5: { 6: int i = 0; 7: double sum = 0; 8: double x = 0.1; 9: while ( (x > x*i-sum) && (x > sum-x*i) ){ 10: i=i+1; 11: sum =sum + x; 12: printf ("%d %f %f\n",i,x*i,sum ); 13: if (i>=600000){break;} 14: } 15: printf ("%f を %d 回足すと合計が\n",x,i); 16: printf ("%f のはずが\n",x*i); 17: printf ("%f になります\n",sum ); 18: printf ("%f だけ違います\n",x*i-sum ); 19: return 0; 20: }
double
float
を double
に換えました。これで精度が上がります。二進表現での精度(計算の細かさ)は52+1で53ビットです。十進表現での精度に直すとほぼ15桁の精度です。break;
実行結果はこうなります。
~/c$ ./k0603 ....(略).... 599989 59998.900000 59998.899999 599990 59999.000000 59998.999999 599991 59999.100000 59999.099999 599992 59999.200000 59999.199999 599993 59999.300000 59999.299999 599994 59999.400000 59999.399999 599995 59999.500000 59999.499999 599996 59999.600000 59999.599999 599997 59999.700000 59999.699999 599998 59999.800000 59999.799999 599999 59999.900000 59999.899999 600000 60000.000000 59999.999999 0.100000 を 600000 回足すと合計が 60000.000000 のはずが 59999.999999 になります 0.000001 だけ違います
いろいろな条件を組み合わせて使うための演算子です。
論理演算子 | 意味 | 説明 | 真になる例 | 偽になる例 |
---|---|---|---|---|
! | not (否定) | 後ろにある値を逆にする(真ならば偽) | !0 | !(1==1) |
&& | and (かつ) | 前後にある値が共に真のときだけ真 | 真 && 真 | 真 && 偽, 偽 && 偽 |
|| | or (または) | 前後にある値の少なくとも1つが真ならば真 (前後にある値が共に偽のときだけ偽) |
真 || 真, 真 || 偽 | 偽 || 偽 |
不要でも( )をつけた方が見やすい場合もあります。自信が持てないときはためらわず( )をつけましょう。
演算子(上が優先) | 演算子の種類 |
---|---|
! ++ -- | 否定演算子、インクリメント,ディクリメント |
* / % | 算術演算子 |
+ - | 算術演算子 |
< <= > >= | 比較演算子 |
== != | 比較演算子 |
&& | AND演算子 |
|| | OR演算子 |
= += -= *= /= %= | 代入演算子 |