Decimal benchmark
March 6, 2023
Today I will show you a simple benchmark between 2 library from previous post. Duel between https://github.com/shopspring/decimal (opens in a new tab) with https://github.com/mercari/go-bps (opens in a new tab). The API of both library is similar in calculation but totally different with initialization, get amount, and conversion to string API.
In this benchmark I only compare simple calculation and string conversion.
Simple add calculation
helper function
func decimalAdd(addition decimal.Decimal, n int) decimal.Decimal { result := decimal.NewFromInt(0) for i := 0; i < n; i++ { result = result.Add(addition) } return result}func bpsAdd(addition *bps.BPS, n int) *bps.BPS { result := bps.NewFromAmount(0) for i := 0; i < n; i++ { result = result.Add(addition) } return result}
Benchmark with 0.01 and 0.0000001 addition
func BenchmarkShopspring001DecimalAdd(b *testing.B) { addition := decimal.NewFromFloat(0.01) for n := 0; n < b.N; n++ { b.StopTimer() b.StartTimer() decimalAdd(addition, n) }}func BenchmarkShopspringPPMDecimalAdd(b *testing.B) { addition := decimal.NewFromFloat(0.000001) for n := 0; n < b.N; n++ { b.StopTimer() b.StartTimer() decimalAdd(addition, n) }}func BenchmarkShopspring1000DecimalAdd(b *testing.B) { addition := decimal.NewFromFloat(0.000001) for n := 0; n < b.N; n++ { b.StopTimer() b.StartTimer() decimalAdd(addition, 1000) }}func BenchmarkMercari001BpsAdd(b *testing.B) { addition := bps.NewFromPercentage(1) for n := 0; n < b.N; n++ { b.StopTimer() b.StartTimer() bpsAdd(addition, n) }}func BenchmarkMercariPPMBpsAdd(b *testing.B) { addition := bps.NewFromPPM(big.NewInt(1)) for n := 0; n < b.N; n++ { b.StopTimer() b.StartTimer() bpsAdd(addition, n) }}func BenchmarkMercari1000BpsAdd(b *testing.B) { addition := bps.NewFromPercentage(1) for n := 0; n < b.N; n++ { b.StopTimer() b.StartTimer() bpsAdd(addition, 1000) }}
Conversion to string
func BenchmarkShopspringStringDecimalConvert(b *testing.B) { value := decimal.NewFromFloat(0.000001) for n := 0; n < b.N; n++ { b.StopTimer() b.StartTimer() value.StringFixed(10) }}func BenchmarkMercariStringBpsConvert(b *testing.B) { value := bps.NewFromPPM(big.NewInt(1)) for n := 0; n < b.N; n++ { b.StopTimer() b.StartTimer() value.FloatString(10) }}
Result
Running tool: /home/linuxbrew/.linuxbrew/bin/go test -benchmem -run=^$ -bench ^(BenchmarkShopspring001DecimalAdd|BenchmarkShopspringPPMDecimalAdd|BenchmarkMercari001BpsAdd|BenchmarkMercariPPMBpsAdd|BenchmarkShopspringStringDecimalConvert|BenchmarkMercariStringBpsConvert)$ github.com/h4ckm03d/golang-playground/6-practical-benchmarkgoos: linuxgoarch: amd64pkg: github.com/h4ckm03d/golang-playground/6-practical-benchmarkcpu: Intel(R) Core(TM) i5-7500 CPU @ 3.40GHzBenchmarkShopspring001DecimalAdd-4 10000 389385 ns/op 400041 B/op 10003 allocs/opBenchmarkShopspringPPMDecimalAdd-4 10000 380516 ns/op 400088 B/op 10004 allocs/opBenchmarkMercari001BpsAdd-4 10000 1267632 ns/op 879983 B/op 40000 allocs/opBenchmarkMercariPPMBpsAdd-4 10000 1300074 ns/op 879983 B/op 40000 allocs/opBenchmarkShopspringStringDecimalConvert-4 1000000 1026 ns/op 240 B/op 12 allocs/opBenchmarkMercariStringBpsConvert-4 935912 1164 ns/op 320 B/op 16 allocs/opPASSok github.com/h4ckm03d/golang-playground/6-practical-benchmark 63.276s
The result of calculation above show the shopspring/decimal
is faster and memory allocation is smaller compare to mercari/go-bps
.
But the string conversion of result is pretty similar compared to the calculation result and the winner still shopspring/decimal
.
So the winner is shopspring/decimal
and I think both of them is still fast because the slowest operation takes 1267632ns ~ 1.267632ms ~ 0.001267632 seconds
. The choice is yours now, which one do you prefer?
Check complete codes in the https://github.com/h4ckm03d/golang-playground/blob/master/6-practical-benchmark/decimal_test.go (opens in a new tab)