Decimal benchmark

2 min read Tweet this post

Today I will show you a simple benchmark between 2 library from previous post. Duel between https://github.com/shopspring/decimal with https://github.com/mercari/go-bps. 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.

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
}

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)
	}
}
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)
	}
}
Running tool: /home/linuxbrew/.linuxbrew/bin/go test -benchmem -run=^$ -bench ^(BenchmarkShopspring001DecimalAdd|BenchmarkShopspringPPMDecimalAdd|BenchmarkMercari001BpsAdd|BenchmarkMercariPPMBpsAdd|BenchmarkShopspringStringDecimalConvert|BenchmarkMercariStringBpsConvert)$ github.com/h4ckm03d/golang-playground/6-practical-benchmark

goos: linux
goarch: amd64
pkg: github.com/h4ckm03d/golang-playground/6-practical-benchmark
cpu: Intel(R) Core(TM) i5-7500 CPU @ 3.40GHz
BenchmarkShopspring001DecimalAdd-4          	   10000	    389385 ns/op	  400041 B/op	   10003 allocs/op
BenchmarkShopspringPPMDecimalAdd-4          	   10000	    380516 ns/op	  400088 B/op	   10004 allocs/op
BenchmarkMercari001BpsAdd-4                 	   10000	   1267632 ns/op	  879983 B/op	   40000 allocs/op
BenchmarkMercariPPMBpsAdd-4                 	   10000	   1300074 ns/op	  879983 B/op	   40000 allocs/op
BenchmarkShopspringStringDecimalConvert-4   	 1000000	      1026 ns/op	     240 B/op	      12 allocs/op
BenchmarkMercariStringBpsConvert-4          	  935912	      1164 ns/op	     320 B/op	      16 allocs/op
PASS
ok  	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

go benchmark