<h3 dir="auto">Preamble</h3>
<p dir="auto">In financial computation, base-10 computation is mandatory.<br>
Discussion can be found in the proposal <a href="https://github.com/golang/go/issues/12127" data-hovercard-type="issue" data-hovercard-url="/golang/go/issues/12127/hovercard">proposal: math/big: Decimal #12127</a> for big.Decimal.</p>
<p dir="auto">A numeric type in the standard library usable for financial and commercial applications would be a big plus.</p>
<h3 dir="auto">Existing solutions</h3>
<p dir="auto">For the moment, there exist 14 package that implement base-10 numbers.<br>
<a href="https://godoc.org/?q=decimal" rel="nofollow">https://godoc.org/?q=decimal</a></p>
<p dir="auto">They all seem experimental, except <a href="https://github.com/shopspring/decimal">https://github.com/shopspring/decimal</a> which is used in production.</p>
<p dir="auto">Its Decimal type is defined as:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="type Decimal struct {
    value *big.Int
    exp int32
}"><pre class="notranslate"><code class="notranslate">type Decimal struct {
    value *big.Int
    exp int32
}
</code></pre></div>
<p dir="auto">So, it is a <strong>arbitrary-precision</strong> type. But this proposal is about <strong>fixed-size</strong> decimal type.</p>
<h3 dir="auto">Need to retrieve currency values stored as decimal in SQL databases</h3>
<p dir="auto">Base-10 numbers are primarily used for financial computation, for dealing with currency values.</p>
<p dir="auto">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.</p>
<p dir="auto">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.</p>
<p dir="auto">A simpler data type, <strong>fixed-size 128bits floating-point decimal</strong> would be an optimal trade-off.</p>
<p dir="auto">In the field of decimal data type, the work of Mike Cowlishaw is paramount:<br>
<a href="https://en.wikipedia.org/wiki/Mike_Cowlishaw" rel="nofollow">https://en.wikipedia.org/wiki/Mike_Cowlishaw</a><br>
<a href="http://speleotrove.com/decimal/" rel="nofollow">http://speleotrove.com/decimal/</a></p>
<p dir="auto">Note that the Java implementation of java.math.BigDecimal is based on the work of M. Cowlishaw:<br>
<a href="http://www.drdobbs.com/jvm/fixed-floating-and-exact-computation-wit/184405721" rel="nofollow">http://www.drdobbs.com/jvm/fixed-floating-and-exact-computation-wit/184405721</a></p>
<h3 dir="auto">Financial and commercial applications' requirements</h3>
<p dir="auto">The usual range for monetary values can be estimated as follows.<br>
Assets under management for a very large multinational insurance company is:</p>
<p dir="auto"><code class="notranslate">$265,507,000,000</code></p>
<p dir="auto">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.</p>
<p dir="auto">This means that for a large company, a decimal data type must cope with figures like:</p>
<p dir="auto"><code class="notranslate">100,000,000,000.00000000</code>, that is, 20 significant digits.</p>
<p dir="auto">A <code class="notranslate">decimal128</code> fixed-size data type provides <strong>34 significant digits</strong>, which can easily store these figures.<br>
We can even store USA national debt of $18,000,000,000,000 in it with full precision.</p>
<p dir="auto">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.</p>
<p dir="auto">Smaller datatype like decimal 64bits only has 16 significant digits, which is not enough for financial computation.<br>
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.</p>
<h3 dir="auto">Package for prototyping</h3>
<p dir="auto">So far, there exists no implementation of fixed-size decimal type, so I wrote this package to experiment with it.<br>
It is a thin wrapper around the <a href="http://speleotrove.com/decimal/dnfloat.html" rel="nofollow">decNumber</a> package of Mike Cowlishaw written in C.<br>
Only the decQuad type has been implemented, as it is a 128bits fixed-size data type.</p>
<p dir="auto"><code class="notranslate">decnum.Quad</code> is a floating-point base-10 number with 34 significant digits, and size is 128 bits.<br>
Working with them is almost as easy as working with float64:<br>
- decnum.Quad is a value, and not a pointer.<br>
- all arithmetic is done on values, not pointers.<br>
- computation errors are tracked by denum.Context.</p>
<p dir="auto"><a href="https://github.com/rin01/decnum">https://github.com/rin01/decnum</a><br>
<a href="https://godoc.org/github.com/rin01/decnum" rel="nofollow">https://godoc.org/github.com/rin01/decnum</a></p>
<p dir="auto">This package tries to demonstrate that decnum.Quad is easy to work with, and is a proposal for the base of an API.<br>
<strong>A complete package would implement all functions described in this document:</strong><br>
<a href="http://speleotrove.com/decimal/dnfloat.html" rel="nofollow">http://speleotrove.com/decimal/dnfloat.html</a><br>
The only difference is that values are passed by value instead of pointers.</p>
<pre class="notranslate">go version devel +fb7122476042 Tue May 20 11:42:25 2014 -0400 linux/amd64

The attached reproducer crashes as (must panic):

$ go run 0.go 
fatal error: unexpected signal during runtime execution
[signal 0xb code=0x1 addr=0x0 pc=0x418e67]

runtime stack:
runtime.throw(0x4603e5)
    src/pkg/runtime/panic.c:520 +0x69 fp=0x7fffda3afc90
runtime.sigpanic()
    src/pkg/runtime/os_linux.c:222 +0x3d fp=0x7fffda3afca8
runtime.gostartcallfn(0x7fffda3afd70, 0x0)
    src/pkg/runtime/stack.c:847 +0x27 fp=0x7fffda3afcc8
runtime.newstack()
    src/pkg/runtime/stack.c:831 +0x6e4 fp=0x7fffda3afe10
runtime: unexpected return pc for runtime.newstackcall called from 0x463e88
runtime.newstackcall(0x421f77, 0x1)
    src/pkg/runtime/asm_amd64.s:275 +0x68 fp=0x7fffda3afe18

goroutine 16 [stack growth]:
runtime.newstackcall(0x0, 0xc208022028)
    src/pkg/runtime/asm_amd64.s:239 fp=0x7f60cc945dc8
runtime.panic(0x42d720, 0x4608fc)
    src/pkg/runtime/panic.c:248 +0x18d fp=0x7f60cc945e60
runtime.panicstring(0x4608fc)
    src/pkg/runtime/panic.c:552 +0x12d fp=0x7f60cc945e88
runtime.panicindex()
    src/pkg/runtime/panic.c:466 +0x27 fp=0x7f60cc945e98
main.id10(0xc208002400, 0x430910, 0x3, 0x0)
    0.go:51 +0xf7 fp=0x7f60cc945f18
main.init()
    0.go:22 +0x69 fp=0x7f60cc945f50
runtime.main()
    src/pkg/runtime/proc.c:240 +0xda fp=0x7f60cc945fa8
runtime.goexit()
    src/pkg/runtime/proc.c:1445 fp=0x7f60cc945fb0
created by _rt0_go
    src/pkg/runtime/asm_amd64.s:97 +0x120</pre>
<p dir="auto">Attachments:</p>
<ol dir="auto">
<li><a href="https://storage.googleapis.com/go-attachment/8046/0/0.go" rel="nofollow">0.go</a> (3712 bytes)</li>
</ol>