C言語の基本|浮動小数点数の表示と精度指定

小数は、表示方法を選ぶだけでぐっと読みやすくなる。%fと%e、精度指定を使って、必要な桁を分かりやすく伝えよう。

C言語で整数を表示できるようになったら、次は小数を含む値の表示を確認していきましょう。

プログラムでは、次のような場面で小数を扱います。

  • 温度や湿度を表示する
  • 時間や距離を表示する
  • 金額や平均値を表示する
  • 割合や測定結果を表示する
  • とても小さい値や大きい値を確認する

小数をそのまま表示すると、小数点以下の桁が必要以上に多くなることがあります。反対に、小さすぎる値や大きすぎる値は、通常の小数表記では桁数が増えて読みにくくなります。

そこで役立つのが、printfの書式指定と精度指定です。

%fを使えば通常の小数表記、%eや%Eを使えば指数部付きの形式で表示できます。さらに、%.2fのように書くと、小数点以下の表示桁数を指定できます。

ここでは、次のポイントを順番に確認します。

  • float型とdouble型の基本
  • %fによる通常の小数表示
  • %eと%Eによる指数部付き表示
  • 小数点以下の桁数を決める精度指定
  • 表示時に行われる丸め
  • 通常表記と指数表記の使い分け
  • 変数の型と書式指定の対応

浮動小数点数は整数より少し複雑に見えますが、書式指定の形を分解すれば、それほど難しくありません。実際の表示結果と見比べながら慣れていきましょう。

浮動小数点数とは

浮動小数点数は、小数を含む値や、非常に大きな値、非常に小さな値を扱うためのデータです。

たとえば、次のような値が浮動小数点数です。

3.14
0.00321
123.456
-8.75

C言語では、浮動小数点数を扱う型として、主にfloat型とdouble型を使います。

特徴
float浮動小数点数を扱う基本的な型
doublefloatより広い範囲と高い精度を扱えることが多い型

入門用のプログラムでは、double型を使うことが多くあります。

double temperature = 24.75;
double distance = 12.345;

double型を使えば、整数部分と小数部分を持つ値を変数に保存できます。

ただし、浮動小数点数には表現できる精度に限りがあります。ソースコードに書いた小数が、コンピュータの内部で完全に同じ値として保存されるとは限りません。

そのため、変数に保存されている値と、画面に表示する桁数は分けて考えることが大切です。

printfで浮動小数点数を表示する

printfで浮動小数点数を表示するときは、%f、%e、%Eなどを使います。

書式指定表示形式値が123.456の場合
%f通常の小数表記123.456000
%e小文字のeを使う指数表記1.234560e+02
%E大文字のEを使う指数表記1.234560E+02

どの書式指定を使っても、元になる値は同じです。printfが画面へ表示するときの形式だけが変わります。

%fで通常の小数として表示する

%fは、浮動小数点数を通常の小数表記で表示します。

double price = 123.456;

printf("%f\n", price);

実行結果は次のようになります。

123.456000

%fで精度を省略すると、小数点以下が6桁表示されます。

変数に保存した値は123.456ですが、表示桁数を6桁にそろえるため、末尾に0が追加されています。

変数の値のイメージ:123.456
%fによる表示    :123.456000

追加された0によって、変数の値が変化したわけではありません。printfが表示の形を整えています。

%eで指数部付きの形式にする

%eは、浮動小数点数を指数部付きの形式で表示します。

double price = 123.456;

printf("%e\n", price);

実行結果は次のようになります。

1.234560e+02

この表記は、次の値を表しています。

1.234560 × 10²

10の2乗は100なので、計算すると123.456になります。

指数表記は、次の3つの部分に分けて読むと分かりやすくなります。

1.234560  e  +02
部分意味
1.234560仮数部
e10の累乗を使う指数表記
+0210の2乗を掛ける

eの後ろが正の値なら10の正の累乗、負の値なら10の負の累乗を表します。

%Eでは指数部のEが大文字になる

%Eの働きは%eとほぼ同じです。違いは、指数部の英字が大文字で表示されることです。

double price = 123.456;

printf("%E\n", price);

実行結果は次のとおりです。

1.234560E+02

%eと%Eを比べると、次のようになります。

書式指定表示結果
%e1.234560e+02
%E1.234560E+02

数値としての意味は同じです。表示する資料やプログラム全体の書き方に合わせて使い分けます。

図1:同じ浮動小数点数を3種類の形式で表示する

この図から分かること

1つの浮動小数点数を、%fでは通常の小数、%eと%Eでは指数部付きの形式で表示できます。

表示される文字の形は違いますが、いずれも同じ値を表しています。printfの書式指定が変更するのは、値の見せ方です。

精度を省略すると小数点以下6桁になる

%f、%e、%Eでは、精度を指定しない場合、小数点以下が6桁表示されます。

printf("%f\n", 12.5);
printf("%e\n", 12.5);
printf("%E\n", 12.5);

実行結果は次のとおりです。

12.500000
1.250000e+01
1.250000E+01

%fでは、通常の小数表記における小数点以下が6桁になります。

%eと%Eでは、指数部より前にある仮数部の小数点以下が6桁になります。

書式指定精度を省略したときの表示
%f小数点以下6桁
%e仮数部の小数点以下6桁
%E仮数部の小数点以下6桁

表示された末尾の0も、6桁にそろえるためにprintfが出力したものです。

精度指定とは

精度指定は、小数点以下を何桁表示するかを決める書き方です。

基本的な形は次のとおりです。

%.桁数f

指数表記の場合も、同じ位置に桁数を書きます。

%.桁数e

代表的な例を確認してみましょう。

書式指定意味
%.1f通常表記で小数点以下1桁
%.2f通常表記で小数点以下2桁
%.4f通常表記で小数点以下4桁
%.2e指数表記で小数点以下2桁
%.3E大文字の指数表記で小数点以下3桁

たとえば、値123.456を%.2fで表示すると、次の結果になります。

printf("%.2f\n", 123.456);

123.46

小数点以下2桁まで表示するため、3桁目以降は表示されません。ただ切り捨てられるのではなく、指定した桁数に合わせて丸められます。

精度指定による表示の違い

値123.456を使って表示結果を比較すると、次のようになります。

書式指定表示結果説明
%f123.456000小数点以下6桁
%.1f123.5小数点以下1桁
%.2f123.46小数点以下2桁
%.3f123.456小数点以下3桁
%.4f123.4560小数点以下4桁
%e1.234560e+02仮数部の小数点以下6桁
%.2e1.23e+02仮数部の小数点以下2桁

指定した桁数より元の小数部分が短い場合は、必要な位置まで0が表示されます。

printf("%.4f\n", 12.5);

12.5000

これにより、測定値や金額などの桁数をそろえられます。

通常表記と指数表記を確認しよう

浮動小数点数の表示形式と精度指定を、1つのプログラムで確認してみましょう。

室温の測定値を異なる形式で表示するプログラム

ファイル名:5_4_1.c

#include <stdio.h>

int main(void)
{
    /* 表示する室温の測定値 */
    double room_temperature = 18.7654;

    /* 通常の小数表記で表示する */
    printf("通常の小数表記 : %f\n", room_temperature);

    /* 指数部付きの形式で表示する */
    printf("指数付き表記   : %e\n", room_temperature);
    printf("大文字の指数表記: %E\n", room_temperature);

    /* 小数点以下の精度を指定して表示する */
    printf("小数点以下2桁  : %.2f\n", room_temperature);
    printf("指数表記で2桁  : %.2e\n", room_temperature);

    return 0;
}
実行結果の例
通常の小数表記 : 18.765400
指数付き表記   : 1.876540e+01
大文字の指数表記: 1.876540E+01
小数点以下2桁  : 18.77
指数表記で2桁  : 1.88e+01

double型の変数に測定値を保存している

表示する値は、double型のroom_temperatureに保存しています。

double room_temperature = 18.7654;

変数名から、室温を表す値であることが分かります。小数を含む測定値なので、double型を使用しています。

この変数を複数のprintfに渡し、書式指定による表示の違いを確認します。

%f では18.765400と表示される

最初のprintfでは、%fを使っています。

printf("通常の小数表記 : %f\n", room_temperature);

精度を省略しているため、小数点以下が6桁表示されます。

18.765400

変数に保存した値は18.7654ですが、6桁にそろえるため、末尾に2つの0が表示されています。

%eと%Eでは指数部付きになる

次の2行では、%eと%Eを使っています。

printf("指数付き表記   : %e\n", room_temperature);
printf("大文字の指数表記: %E\n", room_temperature);

表示結果は次のとおりです。

1.876540e+01
1.876540E+01

この値は、次のように読み取れます。

1.876540 × 10¹

10の1乗は10なので、元の18.7654を表しています。

%eと%Eでは、指数を表す英字の大文字と小文字だけが異なります。

%.2fでは小数点以下2桁に丸められる

次のprintfでは、%.2fを使っています。

printf("小数点以下2桁  : %.2f\n", room_temperature);

元の値は18.7654です。小数点以下2桁まで表示するときは、次の桁も考慮して表示が丸められます。

表示したい部分:18.76
次の桁    :5
表示結果   :18.77

そのため、実行結果は18.77になります。

%.2eでも精度を指定できる

指数表記にも精度を指定できます。

printf("指数表記で2桁  : %.2e\n", room_temperature);

表示結果は次のようになります。

1.88e+01

%.2eの2は、仮数部の小数点以下を2桁にする指定です。

1.876540e+01
     ↓
1.88e+01

指数部分の桁数を2桁にする指定ではない点に注意しましょう。

図2:精度指定によって表示が丸められる流れ

この図から分かること

%.2fを指定すると、小数点以下2桁に合わせて値が丸められ、18.77と表示されます。

この丸めはprintfが表示を作るときに行われます。変数room_temperatureに保存されている値が18.77へ書き換えられるわけではありません。

丸めは表示の段階で行われる

精度指定を使うと、指定した桁数に合わせて表示が丸められます。

double value = 7.896;

printf("%.2f\n", value);

実行結果は次のようになります。

7.90

表示結果だけを見ると、変数の値が7.90になったように見えるかもしれません。しかし、valueに代入し直す処理は行われていません。

続けて精度を変えて表示すると、元の値が残っていることを確認できます。

printf("%.2f\n", value);
printf("%.3f\n", value);

7.90
7.896

1行目では小数点以下2桁、2行目では小数点以下3桁で、同じ変数を表示しています。

変数に保存されている値
        ↓
printfが指定された桁数に整える
        ↓
整えた文字を画面に表示

printfは表示する文字の形を作る関数です。変数へ値を代入する関数ではありません。

浮動小数点数では最後の桁が予想と違うことがある

浮動小数点数は、コンピュータ内部で2進数を使って表現されます。10進数の小数には、2進数で正確に表せないものがあります。

そのため、内部にはソースコードに書いた値と非常に近い値が保存されることがあります。

精度指定によって丸めたとき、境界付近の値では最後の桁が予想と異なる場合があります。これはprintfの故障ではなく、浮動小数点数の表現方法によるものです。

入門段階では、次の2点を覚えておけば大丈夫です。

  • 精度指定は表示する小数点以下の桁数を決める
  • 浮動小数点数は内部的にわずかな誤差を含むことがある

%fが向いている表示

%fは、普段見慣れている小数の形で値を表示したい場合に向いています。

たとえば、次のようなデータです。

  • 気温
  • 金額
  • 時間
  • 距離
  • 平均点
  • 割合
double temperature = 24.5;
double price = 1280.75;

printf("気温は%.1f度です\n", temperature);
printf("価格は%.2f円です\n", price);

気温は24.5度です
価格は1280.75円です

利用者に見せる通常の数値は、%fと精度指定を組み合わせると読みやすくなります。

表示する内容書式指定の例表示例
気温%.1f24.5
金額%.2f1280.75
測定値%.3f12.345

必要な桁数は、扱うデータの目的に合わせて選びます。

%eが向いている表示

%eは、通常の小数表記では長くなりすぎる値に向いています。

たとえば、非常に小さい値を%fで表示すると、0が多く並びます。

0.000000120

指数表記なら、値の大きさを短く表せます。

1.20e-07

非常に大きな値でも同じです。

345000000

指数表記では、次のように表示できます。

3.45e+08

%eが特に役立つ場面には、次のものがあります。

  • 非常に小さい測定値
  • 非常に大きい計算結果
  • 科学技術計算
  • 数値の桁の大きさを確認するデバッグ
  • 通常表記では0が多く並ぶ値

小さい値を%fと%eで比べてみよう

通常の小数表記と指数表記を並べると、それぞれの特徴を比較できます。

小さい測定値を通常表記と指数表記で表示するプログラム

ファイル名:5_4_2.c

#include <stdio.h>

int main(void)
{
    /* センサーから得た小さい測定値 */
    double sensor_value = 0.000456;

    /* 精度を省略して2種類の形式で表示する */
    printf("通常表記と指数表記: %f (%e)\n",
           sensor_value, sensor_value);

    /* それぞれの精度を指定して表示する */
    printf("精度指定あり      : %.6f (%.3e)\n",
           sensor_value, sensor_value);

    return 0;
}
実行結果の例
通常表記と指数表記: 0.000456 (4.560000e-04)
精度指定あり      : 0.000456 (4.560e-04)

同じ変数を2回渡している

最初のprintfには、%fと%eの2つの書式指定があります。

printf("通常表記と指数表記: %f (%e)\n",
       sensor_value, sensor_value);

そのため、sensor_valueも2回渡しています。

書式指定対応する引数表示結果
%f1つ目のsensor_value0.000456
%e2つ目のsensor_value4.560000e-04

どちらも同じ値ですが、表示方法が異なります。

e-04の意味

指数表記の4.560000e-04は、次の値を表します。

4.560000 × 10⁻⁴

10のマイナス4乗は0.0001です。

4.560000 × 0.0001
=0.000456

そのため、通常表記の0.000456と指数表記の4.560000e-04は、同じ値です。

指数部の符号は、値の大きさを読み取る手がかりになります。

指数部意味
e+0210の2乗を掛ける
e+0810の8乗を掛ける
e-0310のマイナス3乗を掛ける
e-0410のマイナス4乗を掛ける

%.3eで仮数部の桁数を調整している

2つ目のprintfでは、指数表記に%.3eを指定しています。

printf("精度指定あり      : %.6f (%.3e)\n",
       sensor_value, sensor_value);

%.3eは、仮数部の小数点以下を3桁にする指定です。

精度指定なし:4.560000e-04
%.3e    :4.560e-04

指数部のe-04は変わっていません。仮数部の末尾にあった0が減り、表示が短くなっています。

書式指定を分解して読もう

精度指定を含む書式は、左から順番に分けると読みやすくなります。

%.3e
部分意味
%書式指定の開始
.精度指定の開始
3小数点以下を3桁にする
e指数部付きの形式で表示する

%.2fも同じ考え方で読めます。

部分意味
%書式指定の開始
.精度指定の開始
2小数点以下を2桁にする
f通常の小数表記で表示する

書式指定の末尾を見ると表示形式が分かり、その前にある数字を見ると小数点以下の桁数が分かります。

図3:浮動小数点数の書式指定を分解して読む

この図から分かること

%.2fは通常表記で小数点以下2桁、%.3eは指数表記で仮数部の小数点以下3桁を表示する指定です。

精度を表す数字を変えれば、%.1f、%.4f、%.2eのような書式も同じ考え方で読み取れます。

double型には%fや%eを使う

printfでdouble型の値を表示するときは、%f、%e、%Eを使用します。

double value = 12.345;

printf("%f\n", value);
printf("%e\n", value);

%dはint型の整数を表示するための書式指定です。double型の値には使用できません。

double value = 12.345;

printf("%d\n", value);

この組み合わせでは型と書式指定が一致していないため、正しい動作は保証されません。

基本的な対応は次のとおりです。

データ型主な書式指定
int%d
double%f、%e、%E

コンパイラから書式に関する警告が表示された場合は、変数の型と書式指定が一致しているか確認しましょう。

float型の値もprintfでは%fを使う

float型の変数をprintfに渡すと、引数として渡されるときにdouble型へ変換されます。そのため、float型の表示にも%fや%eを使用します。

float rate = 12.5f;

printf("%f\n", rate);
printf("%e\n", rate);

実行結果は次のようになります。

12.500000
1.250000e+01

入門段階では、次のように覚えておくと分かりやすいでしょう。

  • printfで通常の小数表示をするなら%f
  • printfで指数表記をするなら%eまたは%E
  • 表示桁数を指定するなら%.2fや%.3e

printfの%fとscanfの%fは扱いが異なる

printfでは、float型もdouble型も%fで表示できます。一方、scanfで入力を受け取る場合は、変数の型によって指定が異なります。

関数float型double型
printf%f%f
scanf%f%lf

printfの書式とscanfの書式は、見た目が似ていても同じルールではありません。

今回の中心はprintfによる表示ですが、入力処理でscanfを使うときには、double型に%lfを使用する点を混同しないようにしましょう。

よくある間違いを確認しよう

浮動小数点数の表示では、書式指定や精度の意味を取り違えやすいところがあります。

精度を指定せず、桁数が多いと感じる

double price = 850.5;

printf("%f\n", price);

実行結果は次のようになります。

850.500000

%fの既定の精度は小数点以下6桁です。金額として小数点以下2桁だけ表示したい場合は、%.2fを使用します。

printf("%.2f\n", price);

850.50

double型の値を%dで表示する

double average = 82.5;

printf("%d\n", average);

%dはint型用です。double型には%fを使用します。

printf("%.1f\n", average);

精度指定で変数の値が変わったと思ってしまう

double value = 3.14159;

printf("%.2f\n", value);
printf("%.5f\n", value);

実行結果は次のとおりです。

3.14
3.14159

最初のprintfで3.14と表示されても、valueの中身は3.14159のままです。そのため、次のprintfでは小数点以下5桁まで表示できます。

%.2eの2を指数部の桁数だと考えてしまう

printf("%.2e\n", 123.456);

1.23e+02

2が指定しているのは、仮数部1.23の小数点以下の桁数です。指数部+02の桁数を指定しているわけではありません。

表示する目的から書式を選ぼう

浮動小数点数の表示形式は、値の用途と読み手に合わせて選ぶことが大切です。

表示したい内容適した書式の例理由
温度%.1f小数点以下1桁で読みやすい
金額%.2f小数点以下2桁にそろえられる
細かな測定値%.4f必要な小数部分を多めに確認できる
非常に小さい値%.3e0の並びを短くできる
非常に大きい値%.3e数値の桁の大きさを把握しやすい
精度を広く確認したい値%fまたは%e既定で小数点以下6桁を確認できる

利用者に見せる結果なら、必要な桁だけに絞ると読みやすくなります。デバッグで値を確認するときは、精度を増やしたり指数表記を使ったりすると、数値の状態を把握しやすくなります。

まずは、同じdouble型の変数を%f、%.2f、%e、%.3eで表示し、見え方を比べてみてください。書式を変えても変数の中身は変わらないことが分かると、目的に応じた表示方法を選びやすくなります。