Issue 1:
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.

Issue 2:
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

Attachments:

0.go (3712 bytes)