Description
Preamble
In financial computation, base-10 computation is mandatory.
Discussion can be found in the proposal proposal: math/big: Decimal #12127 for big.Decimal.
A numeric type in the standard library usable for financial and commercial applications would be a big plus.
Existing solutions
For the moment, there exist 14 package that implement base-10 numbers.
https://godoc.org/?q=decimal
They all seem experimental, except https://github.com/shopspring/decimal which is used in production.
Its Decimal type is defined as:
type Decimal struct {
value *big.Int
exp int32
}
So, it is a arbitrary-precision type. But this proposal is about fixed-size decimal type.
Need to retrieve currency values stored as decimal in SQL databases
Base-10 numbers are primarily used for financial computation, for dealing with currency values.
These values are already stored as base-10 fixed-point datatypes (NUMERIC, DECIMAL, MONEY) in SQL databases (MySQL, MS SQL Server, Oracle, etc), but working with them in Go is not so easy.
Even if a big.Decimal type would eventually be added, the API of package math/big is more complex that what is needed for most financial or commercial applications.
A simpler data type, fixed-size 128bits floating-point decimal would be an optimal trade-off.
In the field of decimal data type, the work of Mike Cowlishaw is paramount:
https://en.wikipedia.org/wiki/Mike_Cowlishaw
http://speleotrove.com/decimal/
Note that the Java implementation of java.math.BigDecimal is based on the work of M. Cowlishaw:
http://www.drdobbs.com/jvm/fixed-floating-and-exact-computation-wit/184405721
Financial and commercial applications' requirements
The usual range for monetary values can be estimated as follows.
Assets under management for a very large multinational insurance company is:
$265,507,000,000
This figure is the sum of amounts that can have 8 digits after decimal point, because this precision is needed when working with foreign currency conversion.
This means that for a large company, a decimal data type must cope with figures like:
100,000,000,000.00000000
, that is, 20 significant digits.
A decimal128
fixed-size data type provides 34 significant digits, which can easily store these figures.
We can even store USA national debt of $18,000,000,000,000 in it with full precision.
When doing financial computation, intermediate calculation can require some more digits, and 34 significant digits of decimal128 can easily provide them for most real cases of financial computation.
Smaller datatype like decimal 64bits only has 16 significant digits, which is not enough for financial computation.
It is always possible to save them with the proper precision in SQL database tables, to spare storage, but to make arithmetic on them, it is safer to always use a decimal 128bits.
Package for prototyping
So far, there exists no implementation of fixed-size decimal type, so I wrote this package to experiment with it.
It is a thin wrapper around the decNumber package of Mike Cowlishaw written in C.
Only the decQuad type has been implemented, as it is a 128bits fixed-size data type.
decnum.Quad
is a floating-point base-10 number with 34 significant digits, and size is 128 bits.
Working with them is almost as easy as working with float64:
- decnum.Quad is a value, and not a pointer.
- all arithmetic is done on values, not pointers.
- computation errors are tracked by denum.Context.
https://github.com/rin01/decnum
https://godoc.org/github.com/rin01/decnum
This package tries to demonstrate that decnum.Quad is easy to work with, and is a proposal for the base of an API.
A complete package would implement all functions described in this document:
http://speleotrove.com/decimal/dnfloat.html
The only difference is that values are passed by value instead of pointers.