mirror of
https://github.com/shopspring/decimal.git
synced 2024-11-22 20:40:48 +01:00
add FAQ to README
This commit is contained in:
parent
354b07a0fb
commit
1a6d69cb90
1 changed files with 58 additions and 1 deletions
59
README.md
59
README.md
|
@ -42,7 +42,7 @@ func main() {
|
||||||
preTax := subtotal.Mul(fee.Add(decimal.NewFromFloat(1)))
|
preTax := subtotal.Mul(fee.Add(decimal.NewFromFloat(1)))
|
||||||
|
|
||||||
total := preTax.Mul(taxRate.Add(decimal.NewFromFloat(1)))
|
total := preTax.Mul(taxRate.Add(decimal.NewFromFloat(1)))
|
||||||
|
|
||||||
fmt.Println("Subtotal:", subtotal) // Subtotal: 408.06
|
fmt.Println("Subtotal:", subtotal) // Subtotal: 408.06
|
||||||
fmt.Println("Pre-tax:", preTax) // Pre-tax: 422.3421
|
fmt.Println("Pre-tax:", preTax) // Pre-tax: 422.3421
|
||||||
fmt.Println("Taxes:", total.Sub(preTax)) // Taxes: 37.482861375
|
fmt.Println("Taxes:", total.Sub(preTax)) // Taxes: 37.482861375
|
||||||
|
@ -60,6 +60,63 @@ http://godoc.org/github.com/shopspring/decimal
|
||||||
* [Spring](https://shopspring.com/), since August 14, 2014.
|
* [Spring](https://shopspring.com/), since August 14, 2014.
|
||||||
* If you are using this in production, please let us know!
|
* If you are using this in production, please let us know!
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
#### Why don't you just use float64?
|
||||||
|
|
||||||
|
Because float64s (or any binary floating point type, actually) can't represent
|
||||||
|
numbers such as 0.1 exactly.
|
||||||
|
|
||||||
|
Consider this code: http://play.golang.org/p/TQBd4yJe6B You might expect that
|
||||||
|
it prints out `10`, but it actually prints `9.999999999999831`. Over time,
|
||||||
|
these small errors can really add up!
|
||||||
|
|
||||||
|
#### Why don't you just use big.Rat?
|
||||||
|
|
||||||
|
big.Rat is fine for representing rational numbers, but Decimal is better for
|
||||||
|
representing money. Why? Here's a (contrived) example:
|
||||||
|
|
||||||
|
Let's say you use big.Rat, and you have two numbers, x and y, both
|
||||||
|
representing 1/3, and you have `z = 1 - x - y = 1/3`. If you print each one
|
||||||
|
out, the string output has to stop somewhere (let's say it stops at 3 decimal
|
||||||
|
digits, for simplicity), so you'll get 0.333, 0.333, and 0.333. But where did
|
||||||
|
the other 0.001 go?
|
||||||
|
|
||||||
|
Here's the above example as code: http://play.golang.org/p/lCZZs0w9KE
|
||||||
|
|
||||||
|
With Decimal, the strings being printed out represent the number exactly. So,
|
||||||
|
if you have `x = y = 1/3` (with precision 3), they will actually be equal to
|
||||||
|
0.333, and when you do `z = 1 - x - y`, `z` will be equal to .334. No money is
|
||||||
|
unaccounted for!
|
||||||
|
|
||||||
|
You still have to be careful. If you want to split a number `N` 3 ways, you
|
||||||
|
can't just send `N/3` to three different people. You have to pick one to send
|
||||||
|
`N - (2/3*N)` to. That person will receive the fraction of a penny remainder.
|
||||||
|
|
||||||
|
But, it is much easier to be careful with Decimal than with big.Rat.
|
||||||
|
|
||||||
|
#### Why isn't the API similar to big.Int's?
|
||||||
|
|
||||||
|
big.Int's API is built to reduce the number of memory allocations for maximal
|
||||||
|
performance. This makes sense for its use-case, but the trade-off is that the
|
||||||
|
API is awkward and easy to misuse.
|
||||||
|
|
||||||
|
For example, to add two big.Ints, you do: `z := new(big.Int).Add(x, y)`. A
|
||||||
|
developer unfamiliar with this API might try to do `z := a.Add(a, b)`. This
|
||||||
|
modifies `a` and sets `z` as an alias for `a`, which they might not expect. It
|
||||||
|
also modifies any other aliases to `a`.
|
||||||
|
|
||||||
|
Here's an example of the subtle bugs you can introduce with big.Int's API:
|
||||||
|
https://play.golang.org/p/x2R_78pa8r
|
||||||
|
|
||||||
|
In contrast, it's difficult to make such mistakes with decimal. Decimals
|
||||||
|
behave like other go numbers types: even though `a = b` will not deep copy
|
||||||
|
`b` into `a`, it is impossible to modify a Decimal, since all Decimal methods
|
||||||
|
return new Decimals and do not modify the originals. The downside is that
|
||||||
|
this causes extra allocations, so Decimal is less performant. My assumption
|
||||||
|
is that if you're using Decimals, you probably care more about correctness
|
||||||
|
than performance.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
Loading…
Reference in a new issue