• Stars
    star
    23
  • Rank 981,978 (Top 20 %)
  • Language
    Go
  • License
    MIT License
  • Created almost 2 years ago
  • Updated 6 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

🧧 Fixed-Point Decimal Money

🧧 Fixed-Point Decimal Money

codecov Go Report Card Go Reference Mentioned in Awesome Go OpenSSF Scorecard

Be Precise: using floats to represent currency is almost criminal. — Robert.C.Martin, "Clean Code" p.301

  • as fast as int64
  • no float in parsing nor printing, does not leak precision
  • ISO 4217 currency
  • block mismatched currency arithmetics
  • 100 LOC
  • fuzz tests
var BuySP500Price = fpmoney.FromInt(9000, fpmoney.SGD)

input := []byte(`{"sp500": {"amount": 9000.02, "currency": "SGD"}}`)

type Stonks struct {
    SP500 fpmoney.Amount `json:"sp500"`
}
var v Stonks
if err := json.Unmarshal(input, &v); err != nil {
    log.Fatal(err)
}

amountToBuy := fpmoney.FromInt(0, fpmoney.SGD)
if v.SP500.GreaterThan(BuySP500Price) {
    amountToBuy = amountToBuy.Add(v.SP500.Mul(2))
}

fmt.Println(amountToBuy)
// Output: 18000.04 SGD

Ultra Small Fractions

Some denominations have very low fractions. Storing them int64 you would get.

  • BTC satoshi is 1 BTC = 100,000,000 satoshi, which is still enough for ~92,233,720,368 BTC.
  • ETH wei is 1 ETH = 1,000,000,000,000,000,000 wei, which is ~9 ETH. If you deal with wei, you may consider bigint or multiple int64. In fact, official Ethereum code is in Go and it is using bigint (code).

Benchmarks

$ go test -bench=. -benchmem . > fpmoney.bench
$ go test -bench=. -benchmem ./internal/bench/float32 > float32.bench
$ go test -bench=. -benchmem ./internal/bench/int > int.bench
$ benchstat -split="XYZ" int.bench float32.bench fpmoney.bench
name \ time/op              int.bench   float32.bench  fpmoney.bench
JSONUnmarshal/small-16      383ns ± 0%     408ns ± 0%     294ns ± 0%
JSONUnmarshal/large-16      436ns ± 0%     473ns ± 0%     365ns ± 0%
JSONMarshal/small-16        115ns ± 0%     158ns ± 0%     226ns ± 0%
JSONMarshal/large-16        112ns ± 0%     146ns ± 0%     272ns ± 0%

name \ alloc/op             int.bench   float32.bench  fpmoney.bench
JSONUnmarshal/small-16       268B ± 0%      270B ± 0%      198B ± 0%
JSONUnmarshal/large-16       272B ± 0%      288B ± 0%      216B ± 0%
JSONMarshal/small-16        57.0B ± 0%     66.0B ± 0%    160.0B ± 0%
JSONMarshal/large-16        72.0B ± 0%     72.0B ± 0%    176.0B ± 0%

name \ allocs/op            int.bench   float32.bench  fpmoney.bench
JSONUnmarshal/small-16       6.00 ± 0%      6.00 ± 0%      3.00 ± 0%
JSONUnmarshal/large-16       6.00 ± 0%      6.00 ± 0%      3.00 ± 0%
JSONMarshal/small-16         2.00 ± 0%      2.00 ± 0%      3.00 ± 0%
JSONMarshal/large-16         2.00 ± 0%      2.00 ± 0%      3.00 ± 0%
goos: darwin
goarch: arm64
pkg: github.com/nikolaydubina/fpmoney
BenchmarkArithmetic/add_x1-16         1000000000	         0.54 ns/op	       0 B/op	       0 allocs/op
BenchmarkArithmetic/add_x100-16       	26382420	        44.42 ns/op	       0 B/op	       0 allocs/op
PASS
ok  	github.com/nikolaydubina/fpmoney	14.200s

References and Related Work

  • ferdypruis/iso4217 was a good inspiration and reference material. it was used in early version as well. it is well maintained and fast library for currencies.
  • github.com/shopspring/decimal: fixed precision; faster printing/parsing/arithmetics; currency handling
  • github.com/Rhymond/go-money: does not use float or interface{} in parsing; currency is enum
  • github.com/ferdypruis/iso4217: skipped deprecated currencies to fit into uint8 and smaller struct size

More Repositories

1

go-recipes

🦩 Tools for Go projects
Go
3,747
star
2

go-binsize-treemap

🔍 Go binary size SVG treemap
Go
441
star
3

calendarheatmap

📅 Calendar heatmap inspired by GitHub contribution activity
Go
384
star
4

go-cover-treemap

🎄 Go code coverage to SVG treemap
Go
258
star
5

llama2.go

LLaMA-2 in native Go
Go
166
star
6

treemap

🍬 Pretty Treemaps
Go
127
star
7

go-instrument

⚡️ Automatically add Trace Spans to Go methods and functions
Go
122
star
8

go-featureprocessing

🔥 Fast, simple sklearn-like feature processing for Go
Go
107
star
9

go-graph-layout

🔮 Graph Layout Algorithms in Go
Go
78
star
10

go-cover-treemap-web

Go
77
star
11

jsonl-graph

🏝 JSONL Graph Tools
Go
69
star
12

import-graph

🕵🏻‍♂️ Collect data about your dependencies
Go
37
star
13

go-ml-benchmarks

⏱ Benchmarks of machine learning inference for Go
Go
29
star
14

watchhttp

🌺 Run command periodically and expose latest STDOUT as HTTP endpoint
Go
28
star
15

fpdecimal

🛫 Fixed-Point Decimals
Go
26
star
16

validate

🥬 validate. simply.
Go
17
star
17

hq

🐁 happy little queue
Go
15
star
18

neuroscience-landscape

🌌 Resources on Neuroscience
12
star
19

vertfn

Go linter for Vertical Function Ordering
Go
11
star
20

smrcptr

🥞 detect mixing pointer and value method receivers
Go
10
star
21

multiline-jsonl

Read and write multiline JSONL in Go
Go
5
star
22

openapi-inline-examples

🌏 Inline OpenAPI JSON examples from filenames
Go
5
star
23

htmljson

🫐 Rich rendering of JSON as HTML in Go
Go
5
star
24

go-enum-example

Go Enum: benchmarks, examples, analysis
Go
4
star
25

htmlyaml

🐹 render YAML as HTML in Go
Go
3
star
26

rchan

rchan: Go channel through Redis List
Go
3
star
27

go-commentage

🐢 how far Go comments drifting behind
Go
2
star
28

svgpan

Pan and Zoom of SVG in your Go front-end app in browser.
Go
2
star
29

go-bench-errors

Benchmarking Go errors
Go
2
star
30

mini-awesome-cv

📝 LaTeX Awesome-CV under 200LOC
TeX
2
star
31

go-enum-encoding

Generate Go enum encoding
Go
2
star
32

consistentimports

Detect inconsistent import aliases
Go
1
star
33

go-instrument-example

Go
1
star
34

go-callsite-stats

analyse function callsites
Go
1
star
35

mdpage

🍙 CLI tool to generate one-page Markdown lists based on YAML
Go
1
star