skip to content

In Go's fmt, how do the %f, %e and %g verbs differ when printing a float64?

level: juniorimportance: must knowfreq 62%

answer

  1. three ways to spell one number
  2. one of them never shows an exponent
  3. two of them share a default of six
  4. the third prints only what it must
  5. shortest digits that read back the same

basics

~20 s

%f prints decimal digits with no exponent, %e prints scientific notation, and %g picks between them by magnitude. %f and %e default to six digits after the point; %g defaults to the shortest digits that identify the value uniquely.

solid answer

~40 s

All three print a `float64`; they differ in shape and in default precision. `%f` is plain decimal with no exponent and defaults to six places after the point, so `1234.5678` prints as `1234.567800`. `%e` is always scientific, also six places by default: `1.234568e+03`. `%g` chooses exponent form for very large or very small magnitudes and plain decimal otherwise, and its default precision is not six — it is the smallest number of digits that identifies the value uniquely, which is exactly what `%v` and `fmt.Println` use for floats. An explicit precision means different things per verb: for `%f` and `%e` it counts digits after the decimal point, for `%g` it caps total significant digits and trailing zeros are dropped. Width is separate from precision: `%9.2f` means minimum field width nine, precision two.

code

go · 9 lines
go
v := 1234.5678
// 1234.567800 — %f defaults to 6 places after the point
fmt.Printf("%f\n", v)
// 1234.57 — explicit precision counts places after the point
fmt.Printf("%.2f\n", v)
// 1.234568e+03 — %e also defaults to 6 places
fmt.Printf("%e\n", v)
// 1234.5678 — %g (and %v) print the shortest unique digits
fmt.Printf("%g\n", v)

go deeper

for a junior

Be ready to say what each of %f, %e and %g prints for a concrete value, and that %f and %e default to six decimals while %g prints the shortest unique form. Knowing that fmt.Println uses %g for floats is the piece most candidates miss.

for a middle

Explain the mechanics: precision means decimal places for %f and %e but significant digits for %g, and %g's default precision is the shortest-unique rule rather than a fixed count. Be able to say when %g flips to exponent form.

for a senior

Show the production judgment: fixed precision is a lossy output format and shortest-unique is not, so pick the verb by whether a human or a parser reads the result. Expect to catch a log or CSV that prints 1e+06 where a downstream tool wanted digits.

for a principal

Own the convention: which formats your services emit for numeric fields, whether human-facing output and machine-facing output are allowed to share a code path, and how that choice is enforced in review rather than rediscovered in a parsing incident.

## The three float verbs Go's `fmt` package formats a `float64` through several verbs. The three you meet every day are `%f`, `%e` and `%g`. - **`%f`** — plain decimal notation, never an exponent: `1234.567800`, `0.000000`. - **`%e`** — scientific notation: one digit before the point, then a signed exponent, `1.234568e+03`. `%E` is identical but uppercases the `e`. - **`%g`** — chooses between the two: exponent form when the value's decimal exponent is very large or very small, plain decimal otherwise, and it never emits trailing zeros. `%G` uppercases the exponent. Underneath, all of them call into `strconv`, whose `FormatFloat` takes the same format bytes `'f'`, `'e'` and `'g'`. So anything true of the verb is true of the `strconv` call and vice versa. ## Default precision is the real difference With no explicit precision, `%f` and `%e` print **six digits after the decimal point** — the C heritage. `%g` has no such fixed default. Its default precision is *the smallest number of digits necessary to represent the value uniquely*: the shortest decimal string that, read back, yields the identical `float64`. This matters because **`%v` for a float is `%g`**, and `fmt.Println` uses `%v`. So: ``` a, b := 0.1, 0.2 fmt.Println(a + b) // 0.30000000000000004 fmt.Printf("%f\n", a+b) // 0.300000 ``` Go is not being pedantic in the first line. The sum of the two nearest `float64` values to 0.1 and 0.2 genuinely is not the nearest `float64` to 0.3, and the shortest-unique rule is what exposes it. `%f` with six places hides it. Neither is wrong; they answer different questions — "what is this value?" versus "how should this value look in a column?". (Write the same expression as a single untyped constant, `fmt.Println(0.1 + 0.2)`, and Go folds it exactly at compile time before it ever becomes a `float64`, so the surprise disappears. Use variables when you want to see runtime float behaviour.) ## What an explicit precision means, verb by verb | Written | Meaning for a float64 | |---|---| | `%.2f` | two digits after the decimal point | | `%.2e` | two digits after the point in the mantissa | | `%.2g` | at most two **significant** digits in total, trailing zeros removed | | `%9.2f` | minimum field width 9, precision 2 (right-aligned, space-padded) | | `%-9.2f` | same, left-aligned | | `%09.2f` | same, zero-padded | | `%+.2f` | always print a sign | Reading `%.3g` as "three digits after the point" is the classic misread; it is three significant digits, so `1234.5` becomes `1.23e+03`. Rounding is to nearest, computed from the exact binary value rather than from an intermediate decimal approximation, so `%.2f` of a value slightly under a half-cent will not round up merely because a shorter print looked like it should. ## When %g switches to exponent form At default precision, `%g` uses exponent form when the value's decimal exponent is below -4 or at least 6. Concretely: ``` fmt.Println(999999.0) // 999999 fmt.Println(1000000.0) // 1e+06 fmt.Println(0.0001) // 0.0001 fmt.Println(0.00001) // 1e-05 ``` This catches people who print quantities, counters or identifiers that happened to arrive as floats (from JSON, say) and are startled to see `1e+06` in a log or a CSV. If the output is consumed by something that expects plain digits, say so with `%.0f` rather than relying on `%v`. ## Choosing a verb - **Human-facing, fixed scale** — a report column, a price, a percentage: `%f` with an explicit precision, plus a width if the column must line up. - **Machine-readable, must be reconstructible** — a wire format, a fixture, a log another program parses: `%g`/`%v` at default precision, or `strconv.FormatFloat(x, 'g', -1, 64)`, which is guaranteed to read back as the same value. A fixed precision is *lossy*; a shortest-unique print is not. - **Wide dynamic range** — physical measurements spanning many orders of magnitude: `%e` or `%g`. There is also `%x`, which prints a hexadecimal floating-point form such as `0x1.34a456d5cfaadp+10`. It is exact and compact, and it is useful in tests and bug reports where you need to name a specific bit pattern without argument. ## Special values Under every one of these verbs, a not-a-number prints as `NaN` and the infinities print as `+Inf` and `-Inf`, and the precision is ignored: `%.2f` of positive infinity is `+Inf`, not `+Inf.00`. Width still applies, so `%8.2f` pads it. ## float32 `fmt` knows the argument's type, so a `float32` is printed with the shortest string that is unique *among float32 values*: `fmt.Println(float32(0.1))` prints `0.1`, while `fmt.Println(float64(float32(0.1)))` prints `0.10000000149011612`. Same bits, different question about which set of values must be distinguished.

  • Which verb does fmt use for a float64 printed with %v or fmt.Println?
    `%g` at default precision. That is why `fmt.Println` on a float shows the shortest decimal that uniquely identifies the value — `0.30000000000000004` rather than `0.300000` — and why it can flip to exponent form, printing `1e+06` for a million.
  • What does the precision in %.3g mean, and how does it differ from %.3f?
    `%.3g` caps the total number of significant digits at three and strips trailing zeros, so `1234.5` prints as `1.23e+03`. `%.3f` counts three digits *after the decimal point*, giving `1234.500`. Misreading `%g`'s precision as decimal places is the common error.
  • How do width and precision combine in a verb like %9.2f?
    Width is the minimum number of columns the field occupies; precision is the digit count. `%9.2f` pads with spaces to at least nine columns and prints two decimals. Add `-` to left-align, `0` to zero-pad, `+` to force the sign. Width never truncates — an oversized number simply overflows the field.

saying these in an interview costs you the question

  • Thinks %v on a float prints six decimals like %f
  • Says %g always uses scientific notation
  • Reads %.3g as three digits after the decimal point
  • Assumes fmt.Println of a float never shows an exponent
  • Believes %f truncates rather than rounds to nearest
  • Confuses the width in %9.2f with the digit count