• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

.gitignoreH A D09-Jul-201811 32

.travis.ymlH A D09-Jul-201899 1410

LICENSEH A D09-Jul-20182.2 KiB4636

README.mdH A D09-Jul-20184.6 KiB12786

decimal-go.goH A D09-Jul-201811 KiB415311

decimal.goH A D09-Jul-201838.2 KiB1,435889

decimal_test.goH A D09-Jul-201874 KiB2,5992,244

rounding.goH A D09-Jul-20183.8 KiB11958

README.md

1# decimal
2
3[![Build Status](https://travis-ci.org/shopspring/decimal.png?branch=master)](https://travis-ci.org/shopspring/decimal) [![GoDoc](https://godoc.org/github.com/shopspring/decimal?status.svg)](https://godoc.org/github.com/shopspring/decimal) [![Go Report Card](https://goreportcard.com/badge/github.com/shopspring/decimal)](https://goreportcard.com/report/github.com/shopspring/decimal)
4
5Arbitrary-precision fixed-point decimal numbers in go.
6
7NOTE: can "only" represent numbers with a maximum of 2^31 digits after the decimal point.
8
9## Features
10
11 * the zero-value is 0, and is safe to use without initialization
12 * addition, subtraction, multiplication with no loss of precision
13 * division with specified precision
14 * database/sql serialization/deserialization
15 * json and xml serialization/deserialization
16
17## Install
18
19Run `go get github.com/shopspring/decimal`
20
21## Usage
22
23```go
24package main
25
26import (
27	"fmt"
28	"github.com/shopspring/decimal"
29)
30
31func main() {
32	price, err := decimal.NewFromString("136.02")
33	if err != nil {
34		panic(err)
35	}
36
37	quantity := decimal.NewFromFloat(3)
38
39	fee, _ := decimal.NewFromString(".035")
40	taxRate, _ := decimal.NewFromString(".08875")
41
42	subtotal := price.Mul(quantity)
43
44	preTax := subtotal.Mul(fee.Add(decimal.NewFromFloat(1)))
45
46	total := preTax.Mul(taxRate.Add(decimal.NewFromFloat(1)))
47
48	fmt.Println("Subtotal:", subtotal)                      // Subtotal: 408.06
49	fmt.Println("Pre-tax:", preTax)                         // Pre-tax: 422.3421
50	fmt.Println("Taxes:", total.Sub(preTax))                // Taxes: 37.482861375
51	fmt.Println("Total:", total)                            // Total: 459.824961375
52	fmt.Println("Tax rate:", total.Sub(preTax).Div(preTax)) // Tax rate: 0.08875
53}
54```
55
56## Documentation
57
58http://godoc.org/github.com/shopspring/decimal
59
60## Production Usage
61
62* [Spring](https://shopspring.com/), since August 14, 2014.
63* If you are using this in production, please let us know!
64
65## FAQ
66
67#### Why don't you just use float64?
68
69Because float64s (or any binary floating point type, actually) can't represent
70numbers such as 0.1 exactly.
71
72Consider this code: http://play.golang.org/p/TQBd4yJe6B You might expect that
73it prints out `10`, but it actually prints `9.999999999999831`. Over time,
74these small errors can really add up!
75
76#### Why don't you just use big.Rat?
77
78big.Rat is fine for representing rational numbers, but Decimal is better for
79representing money. Why? Here's a (contrived) example:
80
81Let's say you use big.Rat, and you have two numbers, x and y, both
82representing 1/3, and you have `z = 1 - x - y = 1/3`. If you print each one
83out, the string output has to stop somewhere (let's say it stops at 3 decimal
84digits, for simplicity), so you'll get 0.333, 0.333, and 0.333. But where did
85the other 0.001 go?
86
87Here's the above example as code: http://play.golang.org/p/lCZZs0w9KE
88
89With Decimal, the strings being printed out represent the number exactly. So,
90if you have `x = y = 1/3` (with precision 3), they will actually be equal to
910.333, and when you do `z = 1 - x - y`, `z` will be equal to .334. No money is
92unaccounted for!
93
94You still have to be careful. If you want to split a number `N` 3 ways, you
95can't just send `N/3` to three different people. You have to pick one to send
96`N - (2/3*N)` to. That person will receive the fraction of a penny remainder.
97
98But, it is much easier to be careful with Decimal than with big.Rat.
99
100#### Why isn't the API similar to big.Int's?
101
102big.Int's API is built to reduce the number of memory allocations for maximal
103performance. This makes sense for its use-case, but the trade-off is that the
104API is awkward and easy to misuse.
105
106For example, to add two big.Ints, you do: `z := new(big.Int).Add(x, y)`. A
107developer unfamiliar with this API might try to do `z := a.Add(a, b)`. This
108modifies `a` and sets `z` as an alias for `a`, which they might not expect. It
109also modifies any other aliases to `a`.
110
111Here's an example of the subtle bugs you can introduce with big.Int's API:
112https://play.golang.org/p/x2R_78pa8r
113
114In contrast, it's difficult to make such mistakes with decimal. Decimals
115behave like other go numbers types: even though `a = b` will not deep copy
116`b` into `a`, it is impossible to modify a Decimal, since all Decimal methods
117return new Decimals and do not modify the originals. The downside is that
118this causes extra allocations, so Decimal is less performant.  My assumption
119is that if you're using Decimals, you probably care more about correctness
120than performance.
121
122## License
123
124The MIT License (MIT)
125
126This is a heavily modified fork of [fpd.Decimal](https://github.com/oguzbilgic/fpd), which was also released under the MIT License.
127