Skip to content

Instantly share code, notes, and snippets.

@koblas
Created March 21, 2025 09:05
Show Gist options
  • Save koblas/6e8ef10641237f33d97e825d56c03022 to your computer and use it in GitHub Desktop.
Save koblas/6e8ef10641237f33d97e825d56c03022 to your computer and use it in GitHub Desktop.
Benchmark of digit counting
package main
import (
"math"
"math/bits"
"strconv"
)
func LogCount(n int) int {
if n == 0 {
return 1
}
return int(math.Log10(float64(n))) + 1
}
func IntCount(n int) int {
cnt := 1
for n > 9 {
n = n / 10
cnt++
}
return cnt
}
func StrCount(n int) int {
s := strconv.FormatInt(int64(n), 10)
return len(s)
}
func BitCount(n int) int {
if n == 0 {
return 1
}
return (bits.Len(uint(n)) * 1233) >> 12
}
func CaseCount(n int) int {
switch {
case n < 10:
return 1
case n < 100:
return 2
case n < 1000:
return 3
case n < 10000:
return 4
case n < 100000:
return 5
case n < 1000000:
return 6
case n < 10000000:
return 7
case n < 100000000:
return 8
case n < 1000000000:
return 9
case n < 10000000000:
return 10
case n < 100000000000:
return 11
case n < 1000000000000:
return 12
case n < 10000000000000:
return 13
case n < 100000000000000:
return 14
case n < 1000000000000000:
return 15
case n < 10000000000000000:
return 16
case n < 100000000000000000:
return 17
case n < 1000000000000000000:
return 18
}
return 19
}
func TreeCount(n int) int {
if n < 10000 { // First major split
if n < 100 { // Second level split
if n < 10 {
return 1
}
return 2
} else { // n >= 100
if n < 1000 {
return 3
}
return 4
}
} else if n < 100000000 { // First major split, second branch
if n < 1000000 { // Second level split
if n < 100000 {
return 5
}
return 6
} else { // n >= 1000000
if n < 10000000 {
return 7
}
return 8
}
} else if n < 1000000000000 { // Third major branch
if n < 10000000000 { // Second level split
if n < 1000000000 {
return 9
}
return 10
} else { // n >= 10000000000
if n < 100000000000 {
return 11
}
return 12
}
} else if n < 10000000000000000 { // Fourth major branch
if n < 100000000000000 { // Second level split
if n < 10000000000000 {
return 13
}
return 14
} else { // n >= 100000000000000
if n < 1000000000000000 {
return 15
}
return 16
}
} else { // Fifth major branch, n >= 10000000000000000
if n < 1000000000000000000 { // Second level split
if n < 100000000000000000 {
return 17
}
return 18
} else { // n >= 1000000000000000000
return 19 // Covering the math.MaxInt64 case
}
}
}
package main
import (
"math"
"testing"
)
func FuzzCount(f *testing.F) {
f.Fuzz(func(t *testing.T, n int) {
if n < 0 {
return
}
lc := LogCount(n)
if v := StrCount(n); lc != v {
t.Errorf("%d: StrCount expected=%d got=%d", n, lc, v)
}
if v := IntCount(n); lc != v {
t.Errorf("%d: IntCount expected=%d got=%d", n, lc, v)
}
// if v := BitCount(n); lc != v {
// t.Errorf("%d: BitCount expected=%d got=%d", n, lc, v)
// }
if v := CaseCount(n); lc != v {
t.Errorf("%d: CaseCount expected=%d got=%d", n, lc, v)
}
if v := TreeCount(n); lc != v {
t.Errorf("%d: TreeCount expected=%d got=%d", n, lc, v)
}
})
}
var sizes = []struct {
key string
value int
}{
{key: "zero", value: 0},
{key: "one", value: 1},
{key: "kilo", value: 1_000},
{key: "mega", value: 1_000_000},
{key: "giga", value: 1_000_000_000},
{key: "max", value: math.MaxInt},
}
func TestCount(t *testing.T) {
for _, item := range sizes {
t.Run(item.key, func(t *testing.T) {
n := item.value
lc := LogCount(n)
if v := StrCount(n); lc != v {
t.Errorf("%d: StrCount expected=%d got=%d", n, lc, v)
}
if v := IntCount(n); lc != v {
t.Errorf("%d: IntCount expected=%d got=%d", n, lc, v)
}
// if v := BitCount(n); lc != v {
// t.Errorf("%d: BitCount expected=%d got=%d", n, lc, v)
// }
if v := CaseCount(n); lc != v {
t.Errorf("%d: CaseCount expected=%d got=%d", n, lc, v)
}
if v := TreeCount(n); lc != v {
t.Errorf("%d: TreeCount expected=%d got=%d", n, lc, v)
}
})
}
}
func BenchmarkLog(b *testing.B) {
for _, item := range sizes {
b.Run(item.key, func(b *testing.B) {
for b.Loop() {
LogCount(item.value)
}
})
}
}
func BenchmarkInt(b *testing.B) {
for _, item := range sizes {
b.Run(item.key, func(b *testing.B) {
for b.Loop() {
IntCount(item.value)
}
})
}
}
func BenchmarkStr(b *testing.B) {
for _, item := range sizes {
b.Run(item.key, func(b *testing.B) {
for b.Loop() {
StrCount(item.value)
}
})
}
}
func BenchmarkCase(b *testing.B) {
for _, item := range sizes {
b.Run(item.key, func(b *testing.B) {
for b.Loop() {
CaseCount(item.value)
}
})
}
}
func BenchmarkTree(b *testing.B) {
for _, item := range sizes {
b.Run(item.key, func(b *testing.B) {
for b.Loop() {
TreeCount(item.value)
}
})
}
}
@koblas
Copy link
Author

koblas commented Mar 21, 2025

For reference the results:

cpu: Apple M1 Max
BenchmarkLog/zero-10            554713105                2.113 ns/op
BenchmarkLog/one-10             202117162                5.948 ns/op
BenchmarkLog/kilo-10            200571992                5.956 ns/op
BenchmarkLog/mega-10            202396642                5.979 ns/op
BenchmarkLog/giga-10            201606382                6.159 ns/op
BenchmarkLog/max-10             201016612                5.980 ns/op
BenchmarkInt/zero-10            607279381                2.004 ns/op
BenchmarkInt/one-10             608492911                2.009 ns/op
BenchmarkInt/kilo-10            336076126                3.535 ns/op
BenchmarkInt/mega-10            267443962                4.483 ns/op
BenchmarkInt/giga-10            221236796                5.435 ns/op
BenchmarkInt/max-10             98998669                12.37 ns/op
BenchmarkStr/zero-10            534139092                2.243 ns/op
BenchmarkStr/one-10             533981032                2.245 ns/op
BenchmarkStr/kilo-10            69896636                17.20 ns/op
BenchmarkStr/mega-10            60761415                19.60 ns/op
BenchmarkStr/giga-10            54514789                22.57 ns/op
BenchmarkStr/max-10             42051223                28.64 ns/op
BenchmarkCase/zero-10           572260392                2.092 ns/op
BenchmarkCase/one-10            577125625                2.118 ns/op
BenchmarkCase/kilo-10           562351724                2.146 ns/op
BenchmarkCase/mega-10           592571253                2.064 ns/op
BenchmarkCase/giga-10           535465575                2.314 ns/op
BenchmarkCase/max-10            326268302                3.645 ns/op
BenchmarkTree/zero-10           549605313                2.193 ns/op
BenchmarkTree/one-10            551538706                2.217 ns/op
BenchmarkTree/kilo-10           563582694                2.179 ns/op
BenchmarkTree/mega-10           543004238                2.218 ns/op
BenchmarkTree/giga-10           595747724                2.021 ns/op
BenchmarkTree/max-10            466222501                2.627 ns/op
PASS

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