Description
Motivation
In many areas, especially in commerce, exact values need to be processed and the inputs are commonly decimal. Unfortunately, decimal values cannot be represented accurately using binary floating points.
Since Go can be used in many places where accurate decimal arithmetic is required it seems reasonable to support it as part of the standard library.
Proposal
The idea is to add math/big Decimal data type that supports integer, fixed-point, and floating-point decimal numbers.
The Decimal API is consistent with Float API when possible.
Internal representation
A Decimal consists of a boolean sign, an arbitrary precision integer unscaled value and a 32-bit integer scale. The value of the number represented by the Decimal is therefore sign × unscaledValue × 10^(-scale)
.
A Decimal (similar to Float) may also be zero (+0, -0) or infinite (+Inf, -Inf). NaN values are not supported.
Each Decimal value also has a precision, rounding mode, and accuracy. The precision is the maximum number of decimal digits available to represent the value. The rounding mode specifies how a result should be rounded to fit into the unscaled value, and accuracy describes the rounding error with respect to the exact result.
The same numerical value can have different representations (with different scales). The rules of arithmetic and rounding specify both the numerical result and the scale used in the result's representation.
Operations
The Decimal type provides operations for
- arithmetic: Add, Sub, Mul, Div, Quo, Rem, QuoRem, Abs
- scale manipulation: Scale, SetScale
- control over rounding behaviour: Mode, SetMode,
- control over precision and accuracy: Prec, SetPrec, Acc
- comparison: Cmp, TotalCmp (http://speleotrove.com/decimal/decifaq4.html#order)
- format conversion: to/from int64, uint64, float32, float64, big.Float, big.Int, big.Rat
- to/from string conversion
Implementation of the above operations closely follows the General Decimal Arithmetic Specification. This specification defines a decimal arithmetic which meets the requirements of commercial, financial, and human-oriented applications. It also matches the decimal arithmetic in the IEEE 754 Standard for Floating Point Arithmetic.
Test cases can be based on General Decimal Arithmetic
Testcases.
IEEE 754 fixed-point types
By setting the desired precision to 7, 16 or 34 and using matching rounding mode (typically ToNearestEven), Decimal operations produce the same results as the corresponding decimal32, decimal64 or decimal128 IEEE-754 arithmetic for operands that correspond to normal (i.e., not denormal) decimal32, decimal64 or decimal128 numbers.
Q&A
- Why floating point?
See https://www.python.org/dev/peps/pep-0327/#why-floating-point - Why are trailing fractional zeros important?
See http://speleotrove.com/decimal/decifaq1.html#tzeros and http://speleotrove.com/decimal/decifaq4.html#unnari - How much precision and range is needed for decimal arithmetic?
See http://speleotrove.com/decimal/decifaq1.html#needed
In particular there is one example where decimal128 doesn't provide enough precision - Why arbitrary precision?
See p3.
Other use-cases: big.Float to string conversion, representing arbitrary precision numbers that are supported in other systems such as databases (for example PostgreSQL decimal can store up to 131072 digits before the decimal point and up to 16383 digits after the decimal point)
Existing packages
- Python: PEP-0327, decimal
- Java: JSR 13, BigDecimal
- ECMA Script proposal: http://wiki.ecmascript.org/doku.php?id=proposals:decimal