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








