liveBook · Manning

Precision

As explained in Learn Go with Pocket-Sized Projects

Numeric precision is the degree of detail or significant accuracy with which a numerical value is represented or computed.

A money converter must keep two kinds of precision straight: how many significant digits its arithmetic can retain, and how many decimal places a currency permits. Confusing them can silently change an amount. section 6.0 section 6.2.6

When a small payment disappears

In Go, float32(100_000_000) - float32(1) still yields 100 million: the one-unit change is beyond float32’s useful precision at that magnitude. float32 provides about six guaranteed decimal digits; float64 provides 15. Even a familiar result may not be exact: math.Sin(math.Pi) produces a tiny nonzero float64, so testing whether it is close enough to zero is more useful than testing == 0. section 6.2.1 section 6.2.3

For decimal money values, store an integer count of subunits alongside a base-10 precision. Thus 1.52 can be represented as 152 subunits with precision 2. Parse the input string directly rather than passing it through a float; keep the representation private so it can change without changing callers. section 6.2.4

Listing 6.6 decimal.go: Decimal struct implementation
// Decimal can represent a floating-point number with a fixed precision.
// example: 
// 1.52 = 152 * 10^(-2) will be stored as {152, 2} #1
type Decimal struct {
    // subunits is the amount of subunits. 
    // Multiply it by the precision to get the real value
    subunits int64 #2
    // Number of "subunits" in a unit, expressed as a power of 10.
    precision byte #3
}

The Decimal definition shows the two fields used to represent a fixed-precision value. section 6.2.4

An amount’s precision must fit its currency. For example, 19.8875 Canadian dollars has four decimal places, exceeding the currency’s two; NewAmount returns ErrTooPrecise. Converted results also need validation against the supported size and currency-precision limits. section 6.2.6 section 6.3.2

To apply an exchange rate, multiply the stored subunit counts and add their precisions, then adjust the result to the target currency’s precision. The shown conversion divides away excess subunits or multiplies to add places; division here truncates, rather than demonstrating a rounding rule. Test ordinary amounts alongside very small rates, large amounts, and changes in target precision. section 6.3.1

Display precision matters too: formatting a currency with two decimal places should print 12.50, not 12.5. Decimal.String uses the precision to pad the fractional part, with a separate case for zero decimal places. section 6.4.3

How Learn Go with Pocket-Sized Projects covers it

How deep it goes
Works through floating-point failures and a fixed-decimal implementation, including parsing and precision adjustment, but does not establish a rounding rule.
Examples
Uses a lost one-euro subtraction, a near-zero sine result, decimal parsing tests, and exchange-rate conversion cases.
What it assumes
Assumes familiarity with Go types, functions, and tests while explaining why floating-point values need care.
What you can do after
Build it from scratch: represent decimal amounts with integer subunits, check currency precision, and test conversion limits.
How it connects
Connects IEEE-754 floating-point arithmetic, fixed-point decimals, currency subunits, exchange rates, validation, and string formatting.

Also explained in

Compare how 9 books explain precision →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Learn Go with Pocket-Sized Projects. The section links point to the parts of the book it draws on.