意外に知らない %.2g の意味
C++20 で追加される(はずの) std::format
のリファレンス実装 fmtlib/fmt を触ってて気づいたメモ。
浮動小数の小数点以下を2桁に抑えたい場合、例えば以下のように書くと思う。
#include <iostream> #include <format> #include <cstdio> int main() { double d = 3.1415926535; ::printf("printf = %.2f", d); // "3.14" std::cout << std::format("format = {:.2}", d); // "3.14" ? return 0; }
だが、これは以下の出力になる。
printf = 3.14 format = 3.1
実は std::format()
で型指定をしない場合、浮動小数型では {:.2g}
として扱われる。
この g
は printf()
にもあるオプションなので、指定してみたら出力が一致した。
double d = 3.1415926535; ::printf("printf = %.2g", d); // "3.1" std::cout << std::format("format = {:.2}", d); // "3.1"
オプションの意味
このように直感に反する結果になってしまったが、そもそも g
とはどんなオプションなのか。
古い仕様書だけど、ISO/IEC 9899:1999 が見つかったので参照してみる。
ISO/IEC 9899:1999 - Programming languages
g,G
A double argument representing a floating-point number is converted in style f or e (or in style F or E in the case of a G conversion specifier), depending on the value converted and the precision.
ということで、g
は入力の精度によって f
(小数点表示) と e
(指数表示) を自動切り替えするオプションであった。
さて、問題の精度指定 %.2g
については、その上に定義が見つかる。
An optional precision that gives the minimum number of digits to appear for the d, i, o, u, x, and X conversions, the number of digits to appear after the decimal-point character for a, A, e, E, f, and F conversions, the maximum number of significant digits for the g and G conversions, or the maximum number of bytes to be written for s conversions.
要点だけ書くと
a
,A
,e
,E
,f
では「小数点以下の桁数」g
,G
では「最大有効桁数」
と定義されていた。
まとめ
つまり、%.2g
は 「浮動小数型の出力を自動で切り替えるけど、有効桁数を2桁にする」という意味だった。
自動切り替えが不要ならば、おとなしく f
か e
を指定しておこう。
double d = 3.1415926535; // 小数点以下が2桁になる ::printf("printf = %.2f", d); // "3.14" std::cout << std::format("format = {:.2f}", d); // "3.14" // 有効桁数が2桁になる ::printf("printf = %.2g", d); // "3.1" std::cout << std::format("format = {:.2g}", d); // "3.1"