
C言語基礎|浮動小数点と繰返し制御
小数でループを回すと、思わぬ落とし穴にハマる。安全に回すコツをやさしく整理!
0.01 を100回足したら 1.0…のはずが?
浮動小数点(float / double)は便利なんだけど、0.01 のような値を“ピッタリ”表せないことがあります。
そのまま繰返し制御に使うと、
- 最後が 1.0 にならず 0.999999… で止まる。
- 1.0 にならないので、終了条件によっては無限ループになる。
みたいなことが起きます。
この記事では、なぜ起きるのかをちゃんと理解して、安全な繰返しの書き方(整数で制御するコツ)まで身につけます。

まず結論:ループの「回数管理」は整数が強い
浮動小数点でループ制御するときの注意点
| やりたいこと | ありがちな書き方 | 起きやすい問題 | おすすめ |
|---|---|---|---|
| 0.0 から 1.0 まで 0.01 ずつ | for (float x=0.0; x<=1.0; x+=0.01) | 誤差が累積して最後が 1.0 にならない | 回数は int で数えて、毎回 x を計算 |
| 1.0 になったら終了 | x != 1.0 を終了条件にする | 1.0 にならず無限ループ | != での比較は避ける |
| 進捗を刻みたい | x を加算で増やす | 細かい刻みほど誤差が目立つ | i / 100.0 のように求め直す |
表の説明
浮動小数点は「近い値」になるだけで、毎回の加算でズレが少しずつ増えることがあります。
そのため、回数や終了判定は整数にしておくと事故が減ります。
どうして誤差が出るの?(やさしく理解)
浮動小数点は内部的には 2進数の小数で表現されます。
ここで重要なのが、10進の 0.01 や 0.1 は 2進の小数で有限桁にならないことが多いという点です。
図:10進の小数が2進で割り切れないイメージ

図の説明
2進で「終わる」小数は 1/2, 1/4, 1/8…みたいな形(0.5, 0.25, 0.125…)が中心です。
0.01 みたいな値は、近い値で近似されるので、加算を繰返すとズレが育ちます。
終了条件に != を使うと危険な理由
たとえば、次のように書くとします。
- x を 0.01 ずつ足していって
- x が 1.0 になったら終わる
でも、x が ピッタリ 1.0 にならない場合があるので、1.0 との比較で止まれません。
浮動小数点の比較で起きること
| 比較 | 期待 | 現実に起こりうること |
|---|---|---|
| x == 1.0 | いつか true になる | ずっと false のままの可能性 |
| x != 1.0 | いつか false になる | ずっと true のままの可能性(無限ループ) |
| x <= 1.0 | どこかで終わる | 終わるが最後が 0.999999… などになりがち |
表の説明
== や != は「完全一致」を要求するので、浮動小数点には不向きです。
終了判定に使うなら「許容誤差(epsilon)」を使う方法もあるけど、回数制御を整数にするのが一番わかりやすく安全です。
サンプルプログラム
- 温度を 0.0℃ → 1.0℃ まで 0.01℃刻みで表示したい
- ただし「危険な方法」と「安全な方法」を並べて確認する
というプログラムの例です。
プロジェクト名:chap7-26-1 ソースファイル名:chap7-26-1.c
// 浮動小数点の加算ループと、整数で制御するループの比較
#include <stdio.h>
int main(void)
{
printf("【比較】0.01ずつ進める処理を2通りで見てみます。\n\n");
// 1) 浮動小数点を加算して進める(誤差が累積しやすい)
printf("■ 方法A:floatを加算して進める\n");
for (float t = 0.0f; t <= 1.0f; t += 0.01f) {
// 端の方で 0.999999 のようにズレが見えることがある
printf("温度A = %.6f\n", t);
}
putchar('\n');
// 2) 整数で回数を管理して、その都度計算(誤差が累積しにくい)
printf("■ 方法B:intで回数管理して、毎回計算する\n");
for (int i = 0; i <= 100; i++) {
float t = i / 100.0f;
printf("温度B = %.6f\n", t);
}
return 0;
}このプログラムで観察できること
- 方法Aは、最後付近で 1.0 ぴったりにならず、0.999999… のように見えることがある
- 方法Bは、毎回 t を i / 100.0 で求め直すので、誤差が積み上がりにくい
(それでも t 自体が完全に表現できるとは限らないけど、ズレが「蓄積」しないのが強み)
登場する命令(構文)と、何をする命令か
for 文
書式
- for (初期化; 条件式; 更新) 文;
何をする命令?
決まった回数や条件の間、処理を繰返します。
このテーマでは「条件式」と「更新」に注意です。
float を更新に使うと誤差が積み重なるので、回数 i を int で持つのがコツです。
printf 関数
書式
- printf(書式文字列, 引数1, 引数2, ...);
何をする命令?
画面に文字や数値を表示します。
今回使う主な変換指定子
| 指定子 | 何を表示 | 例 |
|---|---|---|
| %f | 浮動小数点(double扱い) | %.6f |
| %.6f | 小数点以下6桁で表示 | 0.999999 などが見える |
表の説明
%.6f のように桁数を固定すると、ズレが目で見えて理解しやすくなります。
図で理解:誤差の累積と、求め直しの違い
図:2つの考え方の違い

図の説明
方法Aは “誤差のある値” をさらに足すので、ズレが蓄積しやすいです。
方法Bは “毎回作り直す” ので、ズレが増え続ける形になりにくいです。
16進浮動小数点定数と16進出力(%a / %A)
16進浮動小数点定数の形
- 0x整数部.小数部P指数部接尾語
ポイントは P です。
10進表記の E が 10の指数だったのに対して、ここでは 2の指数になります。
例
| 表記 | イメージ |
|---|---|
| 0x1.23P1 | 16進の 1.23 × 21 |
| 0xA.FP1L | 16進の A.F × 21(long double) |
printf の %a / %A
書式
- printf(%a, 値);
- printf(%A, 値);
何をする命令?
浮動小数点数を 16進の浮動小数点形式で表示します。
誤差を「どういう2進表現になっているか」で確認したいときに便利です。
演習問題
演習7-10:2つの方法を横に並べて表示
float を加算して進める方法と、int を 0..100 で回して i/100.0 を使う方法を、同じ行に並べて表示せよ。
解答例
プロジェクト名:chap7-26-2ソースファイル名:chap7-26-2.c
#include <stdio.h>
int main(void)
{
float a = 0.0f;
printf(" i 加算で進めるA 計算で作るB\n");
for (int i = 0; i <= 100; i++) {
float b = i / 100.0f;
printf("%3d %.10f %.10f\n", i, a, b);
a += 0.01f;
}
return 0;
}解説
- A は誤差が積み上がる。
- B は毎回作るので、ズレが増え続けにくい。
- %.10f のように桁を増やすと差が見やすいです。
演習7-11:合計値を比べて考察する
0.0 から 1.0 まで 0.01刻みの値を全部足した合計を、方法Aと方法Bで求めて表示せよ。結果の違いを観察せよ。
解答例
プロジェクト名:chap7-26-3 ソースファイル名:chap7-26-3.c
#include <stdio.h>
int main(void)
{
float sumA = 0.0f;
float sumB = 0.0f;
// 方法A:加算で進める
for (float x = 0.0f; x <= 1.0f; x += 0.01f) {
sumA += x;
}
// 方法B:整数で制御して毎回計算
for (int i = 0; i <= 100; i++) {
float x = i / 100.0f;
sumB += x;
}
printf("合計A(加算で進める) = %.10f\n", sumA);
printf("合計B(毎回計算する) = %.10f\n", sumB);
return 0;
}解説
- どちらも浮動小数点なので誤差はゼロになりません。
- でも「誤差の増え方」が違うので、合計にも差が出ることがあります。
- 実務では、金額などの累積は整数(最小単位)で扱うのが定番です。
重要ポイント(やさしくまとめ)
- 浮動小数点を繰返し制御の基準にすると、誤差で事故りやすい。
- 終了条件に != を使うのは危険(1.0 にならないことがある)
- ループの回数や判定は int で管理して、浮動小数点値は 毎回計算するのが安全
