What precisely does the %g printf specifier mean?

This is the full description of the g/G specifier in the C11 standard:

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. Let P equal the precision if nonzero, 6 if the precision is
omitted, or 1 if the precision is zero. Then, if a conversion with
style E would have an exponent of X:

     if P > X ≥ −4, the conversion is
with style f (or F) and precision P − (X + 1).
     otherwise, the
conversion is with style e (or E) and precision P − 1.

Finally, unless
the # flag is used, any trailing zeros are removed from the fractional
portion of the result and the decimal-point character is removed if
there is no fractional portion remaining.

A double argument
representing an infinity or NaN is converted in the style of an f or F
conversion specifier.

This behaviour is somewhat similar to simply using the shortest representation out of %f and %e, but not equivalent. There are two important differences:

  • Trailing zeros (and, potentially, the decimal point) get stripped when using %g, which can cause the output of a %g specifier to not exactly match what either %f or %e would’ve produced.
  • The decision about whether to use %f-style or %e-style formatting is made based purely upon the size of the exponent that would be needed in %e-style notation, and does not directly depend on which representation would be shorter. There are several scenarios in which this rule results in %g selecting the longer representation, like the one shown in the question where %g uses scientific notation even though this makes the output 4 characters longer than it needs to be.

In case the C standard’s wording is hard to parse, the Python documentation provides another description of the same behaviour:

General format. For a given precision p >= 1,
this rounds the number to p significant digits and
then formats the result in either fixed-point format
or in scientific notation, depending on its magnitude.

The precise rules are as follows: suppose that the
result formatted with presentation type 'e' and
precision p-1 would have exponent exp. Then
if -4 <= exp < p, the number is formatted
with presentation type 'f' and precision
p-1-exp. Otherwise, the number is formatted
with presentation type 'e' and precision p-1.
In both cases insignificant trailing zeros are removed
from the significand, and the decimal point is also
removed if there are no remaining digits following it.

Positive and negative infinity, positive and negative
zero, and nans, are formatted as inf, -inf,
0, -0 and nan respectively, regardless of
the precision.

A precision of 0 is treated as equivalent to a
precision of 1. The default precision is 6.

The many sources on the internet that claim that %g just picks the shortest out of %e and %f are simply wrong.

Leave a Comment