|
1 | 1 | # decimal
|
2 | 2 |
|
3 |
| -This library implements fixed-precision decimal numbers based on the IEEE 754-2019 standard; |
4 |
| -<https://ieeexplore.ieee.org/document/8766229>. |
5 |
| -More info can be found at: |
6 |
| -<http://speleotrove.com/decimal/> |
| 3 | +This library implements fixed-precision decimal numbers based on the [IEEE 754-2019 standard](https://ieeexplore.ieee.org/document/8766229). |
| 4 | +More info can be found at <http://speleotrove.com/decimal/>. |
7 | 5 |
|
8 | 6 | ## Features
|
9 | 7 |
|
10 | 8 | - Decimal64, partial implementation of the ieee-754R standard
|
11 |
| -- Half up and half even rounding |
| 9 | +- Rounding modes: half up, half even, down (towards zero) |
12 | 10 | - Up to 3 times faster than arbitrary precision decimal libraries in Go
|
13 | 11 |
|
14 | 12 | ## Goals
|
15 | 13 |
|
16 |
| -- Implement 128 bit decimal |
| 14 | +- Implement 128 bit decimal. |
17 | 15 | - Implement as much of <https://speleotrove.com/decimal/decarith.pdf> as possible.
|
18 | 16 |
|
19 | 17 | ## Installation and use
|
20 | 18 |
|
21 |
| -Run `go get github.com/anz-bank/decimal` |
| 19 | +Run `go get github.com/anz-bank/decimal/d64` |
22 | 20 |
|
23 | 21 | ```go
|
24 | 22 | package main
|
25 | 23 |
|
26 | 24 | import (
|
27 | 25 | "fmt"
|
28 | 26 |
|
29 |
| - "github.com/anz-bank/decimal" |
| 27 | + "github.com/anz-bank/decimal/d64" |
30 | 28 | )
|
31 | 29 |
|
32 | 30 | func main() {
|
33 |
| - var a decimal.Decimal64 |
34 |
| - b := decimal.MustParse64("0.1") |
35 |
| - c := decimal.MustParse64("0.3") |
36 |
| - d := decimal.New64FromInt64(123456) |
| 31 | + var a d64.Decimal |
| 32 | + b := d64.MustParse("0.1") |
| 33 | + c := d64.MustParse("0.3") |
| 34 | + d := d64.NewFromInt64(123456) |
37 | 35 |
|
38 | 36 | fmt.Println(a, b, c, d)
|
39 | 37 | }
|
40 | 38 | ```
|
41 | 39 |
|
42 | 40 | ## Usage notes
|
43 | 41 |
|
| 42 | +The d128 package doesn't exist yet, so d64 is assumed below. |
| 43 | + |
44 | 44 | ### Formatting
|
45 | 45 |
|
46 |
| -`Decimal64` provides numerous ways to present numbers for human and machine |
47 |
| -consumption. |
| 46 | +`Decimal` provides numerous ways to present numbers for human and machine consumption. |
48 | 47 |
|
49 |
| -`Decimal64` implements the following conventional interfaces: |
| 48 | +`Decimal` implements the following conventional interfaces: |
50 | 49 |
|
51 | 50 | - `fmt`: `Formatter`, `Scanner` and `Stringer`
|
52 |
| - - It currently supports specifying a precision argument, e.g., `%.10f` for the |
53 |
| - `f` and `F` verbs, while support for `g` and `G` is [planned](https://github.com/anz-bank/decimal/issues/72), as is [support for width specifiers](https://github.com/anz-bank/decimal/issues/72). |
| 51 | + - It currently supports specifying a precision argument, e.g., `%.10f` for the `f` and `F` verbs, while support for `g` and `G` is [planned](https://github.com/anz-bank/decimal/issues/72), as is [support for width specifiers](https://github.com/anz-bank/decimal/issues/72). |
54 | 52 | - `json`: `Marshaller` and `Unmarshaller`
|
55 | 53 | - `encoding`: `BinaryMarshaler`, `BinaryUnmarshaler`, `TextMarshaler` and `TextUnmarshaler`
|
56 |
| -- `encoging/gob`: `GobEncoder` and `GobDecoder` |
| 54 | +- `encoding/gob`: `GobEncoder` and `GobDecoder` |
57 | 55 |
|
58 |
| -The following methods provide more direct access to the internal methods used to |
59 |
| -implement `fmt.Formatter`. (For maximum control, use `fmt.Printf` &co or invoke |
60 |
| -the `fmt.Formatter` interface directly.) |
| 56 | +The following methods provide more direct access to the internal methods used to implement `fmt.Formatter`. |
| 57 | +For maximum control, use `fmt.Printf` &co or invoke the `fmt.Formatter` interface directly. |
61 | 58 |
|
62 |
| -- `Decimal64.Append` formats straight into a `[]byte` buffer. |
63 |
| -- `Decimal64.Text` formats in the same way, but returns a `string`. |
| 59 | +- `Decimal.Append` formats straight into a `[]byte` buffer. |
| 60 | +- `Decimal.Text` formats in the same way, but returns a `string`. |
64 | 61 |
|
65 | 62 | ### Debugging
|
66 | 63 |
|
67 |
| -tl;dr: Use the `decimal_debug` compiler tag during debugging to greatly ease |
68 |
| -runtime inspection of `Decimal64` values. |
| 64 | +tl;dr: Use the `decimal_debug` compiler tag during debugging to greatly ease runtime inspection of `Decimal` values. |
69 | 65 |
|
70 |
| -Debugging with the `decimal` package can be challeging because a `Decimal64` |
71 |
| -number is encoded in a `uint64` and the values it holds are inscrutable even to |
72 |
| -the trained eye. For example, the number one `decimal.One64` is represented |
73 |
| -internally as the number `3450757314565799936` (`2fe38d7ea4c68000` in |
74 |
| -hexadecimal). |
| 66 | +Debugging with the `decimal` package can be challenging because a `Decimal` number is encoded in a `uint64` and the values it holds are inscrutable even to the trained eye. |
| 67 | +For example, the number one `One` is represented internally as the number `3450757314565799936` (`2fe38d7ea4c68000` in hexadecimal). |
75 | 68 |
|
76 |
| -To ease debugging, `Decimal64` holds an optional `debugInfo` structure that |
77 |
| -contains a string representation and unpacked components of the `uint64` |
78 |
| -representation for every `Decimal64` value. |
| 69 | +To ease debugging, `Decimal` holds an optional `debugInfo` structure that contains a string representation and unpacked components of the `uint64` representation for every `Decimal` value. |
79 | 70 |
|
80 |
| -This feature is enabled through the `decimal_debug` compiler tag. This is done |
81 |
| -at compile time instead of through runtime flags because having the structure |
82 |
| -there even if not used would double the size of each number and greatly increase |
83 |
| -the cost of using it. The size and runtime cost of this feature is zero when the |
84 |
| -compiler tag is not present. |
| 71 | +This feature is enabled through the `decimal_debug` compiler tag. |
| 72 | +This is done at compile time instead of through runtime flags because having the structure there, even if not used, would double the size of each number and greatly increase the cost of using it. |
| 73 | +The size and runtime cost of this feature is zero when the compiler tag is not present. |
85 | 74 |
|
86 | 75 | ## Docs
|
87 | 76 |
|
88 | 77 | <https://godoc.org/github.com/anz-bank/decimal>
|
89 | 78 |
|
90 | 79 | ## Why decimal?
|
91 | 80 |
|
92 |
| -Binary floating point numbers are fundamentally flawed when it comes to representing exact numbers in a decimal world. Just like 1/3 can't be represented in base 10 (it evaluates to 0.3333333333 repeating), 1/10 can't be represented in binary. |
| 81 | +Binary floating point numbers are fundamentally flawed when it comes to representing exact numbers in a decimal world. |
| 82 | +Just like 1/3 can't be represented in base 10 (it evaluates to 0.3333333333 repeating), 1/10 can't be represented in binary. |
93 | 83 | The solution is to use a decimal floating point number.
|
94 | 84 | Binary floating point numbers (often just called floating point numbers) are usually in the form `Sign * Significand * 2 ^ exp` and decimal floating point numbers change this to `Sign * Significand * 10 ^ exp`.
|
95 | 85 | The use of base 10 eliminates the decimal fraction problem.
|
96 | 86 |
|
97 | 87 | ## Why fixed precision?
|
98 | 88 |
|
99 |
| -Most implementations of a decimal floating point datatype implement an *arbitrary precision* type, which often uses an underlying big int. This gives flexibility in that as the number grows, the number of bits assigned to the number grows ( hence the term "arbitrary precision"). |
100 |
| -This library is different. It uses a 64-bit decimal datatype as specified in the IEEE-754R standard. This sacrifices the ability to represent arbitrarily large numbers, but is much faster than arbitrary precision libraries. |
| 89 | +Most implementations of a decimal floating point datatype implement an *arbitrary precision* type, which often uses an underlying big int. |
| 90 | +This gives flexibility in that as the number grows, the number of bits assigned to the number grows (hence the term "arbitrary precision"). |
| 91 | +This library is different. |
| 92 | +It uses a 64-bit decimal datatype as specified in the IEEE-754R standard. |
| 93 | +This sacrifices the ability to represent arbitrarily large numbers, but is much faster than arbitrary precision libraries. |
101 | 94 | There are two main reasons for this:
|
102 | 95 |
|
103 |
| -1. The fixed-size data type is a `uint64` under the hood and never requires heap |
104 |
| - allocation. |
105 |
| -2. All the algorithms can hard-code assumptions about the number of bits to work |
106 |
| - with. |
| 96 | +1. The fixed-size data type is a `uint64` under the hood and never requires heap allocation. |
| 97 | +2. All the algorithms can hard-code assumptions about the number of bits to work with. |
107 | 98 | In fact, many of the operations work on the entire number as a single unit
|
108 | 99 | using 64-bit integer arithmetic and, on the occasions it needs to use more,
|
109 | 100 | 128 bits always suffices.
|
0 commit comments