GolangNote

Golang笔记

10进制与36进制互转的方法和性能

Permalink

使用 Go 语言实现10进制与36进制互转及性能,可以使用内置库 strconv 轻松实现。

10进制与36进制互转

利用 strconv 两个函数

Go: strconv
1
2
s := strconv.FormatInt(n, 36)
_, _ = strconv.ParseInt(s, 36, 64)

如果用 Uint 则快一点点,为了更好性能,可以专门对 10 转 36 进制写一个专用库,已经有大神写好了 https://github.com/martinlindhe/base36

因为少了很多判断,直接使用既定预设的情况,速度快很多,截取里面主要部分:

Go: 10进制与36进制互转
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
var (
	base36 = []byte{
		'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
		'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
		'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
		'U', 'V', 'W', 'X', 'Y', 'Z'}
	uint8Index = []uint64{
		0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 1, 2,
		3, 4, 5, 6, 7, 8, 9, 0, 0, 0,
		0, 0, 0, 0, 10, 11, 12, 13, 14,
		15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
		25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
		35, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13,
		14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
		24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
		34, 35, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, // 256
	}
	pow36Index = []uint64{
		1, 36, 1296, 46656, 1679616, 60466176,
		2176782336, 78364164096, 2821109907456,
		101559956668416, 3656158440062976,
		131621703842267136, 4738381338321616896,
		9223372036854775808,
	}
)

// Bs36Encode encodes a number to base36.
func Bs36Encode(value uint64) string {
	var res [16]byte
	var i int
	for i = len(res) - 1; ; i-- {
		res[i] = base36[value%36]
		value /= 36
		if value == 0 {
			break
		}
	}

	return string(res[i:])
}

// Bs36Decode decodes a base36-encoded string.
func Bs36Decode(s string) uint64 {
	if len(s) > 13 {
		s = s[:12]
	}
	res := uint64(0)
	l := len(s) - 1
	for idx := 0; idx < len(s); idx++ {
		c := s[l-idx]
		res += uint8Index[c] * pow36Index[idx]
	}
	return res
}

性能比较

比较代码

Go: 性能比较
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Good 82.41 ns/op
func Benchmark_format36Int(b *testing.B) {
	bn2 := int64(b.N)
	for n := int64(0); n < bn2; n++ {
		s := strconv.FormatInt(n, 36)
		_, _ = strconv.ParseInt(s, 36, 64)
	}
}

// Better 78.93 ns/op
func Benchmark_format36Uint(b *testing.B) {
	bn2 := uint64(b.N)
	for n := uint64(0); n < bn2; n++ {
		s := strconv.FormatUint(n, 36)
		_, _ = strconv.ParseUint(s, 36, 64)
	}
}

// Best 19.97 ns/op
func Benchmark_formatBs36Uint(b *testing.B) {
	bn2 := uint64(b.N)
	for n := uint64(0); n < bn2; n++ {
		s := Bs36Encode(n)
		_ = Bs36Decode(s)
	}
}

比较结果

plaintext: 比较结果
1
2
3
4
5
6
Benchmark_format36Int
Benchmark_format36Int-8      	16581802	        82.41 ns/op	       5 B/op	       0 allocs/op
Benchmark_format36Uint
Benchmark_format36Uint-8     	17468564	        78.93 ns/op	       5 B/op	       0 allocs/op
Benchmark_formatBs36Uint
Benchmark_formatBs36Uint-8   	73328091	        19.97 ns/op	       0 B/op	       0 allocs/op

可以看到,这个特定功能的库速度很快!这个库也考虑了大小写

Go:
1
2
3
4
5
6
7
8
func main() {
	n := uint64(time.Now().Unix())
	s := Bs36Encode(n)
	n2 := Bs36Decode(s)
	fmt.Println(n, s, n2)
	fmt.Println(Bs36Decode("KSX180"))
	fmt.Println(Bs36Decode("Ksx180"))
}

结果:

plaintext: 结果
1
2
3
1257894000 KSX180 1257894000
1257894000
1257894000

本文网址: https://golangnote.com/topic/315.html 转摘请注明来源

Related articles

Golang 泛型性能初识

编程时,我们通常需要编写“泛型”函数,其中确切的数据类型并不重要。例如,您可能想编写一个简单的函数来对数字进行求和。Go 直到最近才有这个概念,但最近才添加了它(从1.18版开始)。...

Write a Comment to "10进制与36进制互转的方法和性能"

Submit Comment Login
Based on Golang + fastHTTP + sdb | go1.18 Processed in 1ms