Skip to content

Instantly share code, notes, and snippets.

@liufuyang
Last active March 21, 2019 08:59
Show Gist options
  • Save liufuyang/a36de53033d989320664e5c242d7d4aa to your computer and use it in GitHub Desktop.
Save liufuyang/a36de53033d989320664e5c242d7d4aa to your computer and use it in GitHub Desktop.
Benchmark function speed to get the length of string of a uint64
package fastlen
import (
"math/rand"
"strconv"
"testing"
)
func LenUint64A(x uint64) int {
return len(strconv.FormatUint(x, 10))
}
var uintSizeTable = [21]uint64{
0,
9, 99, 999, 9999, 99999,
999999, 9999999, 99999999, 999999999, 9999999999,
99999999999, 999999999999, 9999999999999, 99999999999999, 999999999999999,
9999999999999999, 99999999999999999, 999999999999999999, 9999999999999999999,
^uint64(0),
}
func LenUint64B(x uint64) int {
for i := 1; ; i++ {
if x <= uintSizeTable[i] {
return i
}
}
}
func LenUint64B2(x uint64) int {
i := 1
// reduce comparison time for large numbers
if x > 9999 {
i = 5
} else if x > 99 {
i = 3
}
for ; ; i++ {
if x <= uintSizeTable[i] {
return i
}
}
}
func LenUint64C(x uint64) int {
if x > uintSizeTable[3] { // 4 - 20
if x > uintSizeTable[5] { // 6 - 20, mid at 12
if x > uintSizeTable[12] { // 13 - 20, mid at 16
if x > uintSizeTable[16] { // 17 - 20, mid at 18
if x > uintSizeTable[18] { // 19 - 20
if x > uintSizeTable[19] {
return 20
}
return 19
}
// 17 - 18
if x > uintSizeTable[17] {
return 18
}
return 17
}
// 13 - 16, mid at 14
if x > uintSizeTable[14] { // 15 - 16
if x > uintSizeTable[15] {
return 16
}
return 15
}
// 13 - 14
if x > uintSizeTable[13] {
return 14
}
return 13
}
// 6 - 12, mid at 9
if x > uintSizeTable[9] { // 10 - 12, mid at 11
if x > uintSizeTable[11] { // 12 - 12
return 12
}
// 10 - 11
if x > uintSizeTable[10] {
return 11
}
return 10
}
// 6 - 9, mid at 7
if x > uintSizeTable[7] { // 8 - 9
if x > uintSizeTable[8] {
return 9
}
return 8
}
// 6 - 7
if x > uintSizeTable[6] {
return 7
}
return 6
}
// 4 - 5
if x > uintSizeTable[4] {
return 5
}
return 4
}
// 1 - 3
if x > uintSizeTable[1] {
if x > uintSizeTable[2] {
return 3
}
return 2
}
return 1
}
func TestC(t *testing.T) {
for i := 0; i < 100000; i++ {
num := rand.Uint64()
expected := LenUint64A(num)
actual := LenUint64C(num)
if LenUint64A(num) != LenUint64C(num) {
t.Fatalf("Expected %d, Actual %d", expected, actual)
}
}
}
func TestCManually(t *testing.T) {
nums := [22]uint64{0,
1, 12, 123, 1234, 12345,
123456, 1234567, 12345678, 123456789, 1234567890,
1234567891, 12345678912, 123456789123, 1234567891234, 12345678912345,
123456789123456, 1234567891234567, 12345678912345678, 123456789123456789,
123456789123457890,
^uint64(0),
}
for _, num := range nums {
expected := LenUint64A(num)
actual := LenUint64C(num)
if expected != actual {
t.Fatalf("Expected %d, Actual %d", expected, actual)
}
}
}
func BenchmarkFastLenUint_full_range(b *testing.B) {
nums := make([]uint64, 1000000)
for i := range nums {
nums[i] = rand.Uint64()
}
b.Run("A-Original ", func(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
LenUint64A(nums[int(i)%len(nums)])
}
})
b.Run("B-ForLoopTable ", func(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
LenUint64B(nums[int(i)%len(nums)])
}
})
b.Run("B-ForLoopTable-faster", func(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
LenUint64B2(nums[int(i)%len(nums)])
}
})
b.Run("C-BinarySearch ", func(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
LenUint64C(nums[int(i)%len(nums)])
}
})
}
func BenchmarkFastLenUint_0_to_64000(b *testing.B) {
nums := make([]uint64, 1000000)
for i := range nums {
nums[i] = rand.Uint64() % 64000
}
b.Run("A-Original ", func(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
LenUint64A(nums[int(i)%len(nums)])
}
})
b.Run("B-ForLoopTable ", func(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
LenUint64B(nums[int(i)%len(nums)])
}
})
b.Run("B-ForLoopTable-faster", func(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
LenUint64B2(nums[int(i)%len(nums)])
}
})
b.Run("C-BinarySearch ", func(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
LenUint64C(nums[int(i)%len(nums)])
}
})
}
func BenchmarkFastLenUint_0_to_512(b *testing.B) {
nums := make([]uint64, 1000000)
for i := range nums {
nums[i] = rand.Uint64() % 512
}
b.Run("A-Original ", func(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
LenUint64A(nums[int(i)%len(nums)])
}
})
b.Run("B-ForLoopTable ", func(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
LenUint64B(nums[int(i)%len(nums)])
}
})
b.Run("B-ForLoopTable-faster", func(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
LenUint64B2(nums[int(i)%len(nums)])
}
})
b.Run("C-BinarySearch ", func(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
LenUint64C(nums[int(i)%len(nums)])
}
})
}
@liufuyang
Copy link
Author

liufuyang commented Mar 20, 2019

Revison 5 output:

go test -bench BenchmarkFastLenUint
goos: darwin
goarch: amd64
pkg: github.com/liufuyang/tmp
BenchmarkFastLenUint_full_range/A-Original___________-8         	20000000	        84.0 ns/op
BenchmarkFastLenUint_full_range/B-ForLoopTable_______-8         	50000000	        30.6 ns/op
BenchmarkFastLenUint_full_range/B-ForLoopTable-faster-8         	50000000	        29.2 ns/op
BenchmarkFastLenUint_full_range/C-BinarySearch_______-8         	100000000	        21.8 ns/op

BenchmarkFastLenUint_0_to_64000/A-Original___________-8         	30000000	        50.8 ns/op
BenchmarkFastLenUint_0_to_64000/B-ForLoopTable_______-8         	100000000	        17.6 ns/op
BenchmarkFastLenUint_0_to_64000/B-ForLoopTable-faster-8         	100000000	        16.6 ns/op
BenchmarkFastLenUint_0_to_64000/C-BinarySearch_______-8         	100000000	        15.5 ns/op

BenchmarkFastLenUint_0_to_512/A-Original___________-8           	30000000	        41.9 ns/op
BenchmarkFastLenUint_0_to_512/B-ForLoopTable_______-8           	100000000	        17.1 ns/op
BenchmarkFastLenUint_0_to_512/B-ForLoopTable-faster-8           	100000000	        17.5 ns/op
BenchmarkFastLenUint_0_to_512/C-BinarySearch_______-8           	100000000	        16.6 ns/op

PASS
ok  	github.com/liufuyang/tmp	20.217s

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment