2017-10-21 22 views
2

私は16進数を16進数に変換しようとしています。そして、16進数を表す4文字の文字列を得るために0でパディングしています。intをHex文字列に変換し、Golangで0を埋め込む効率的な方法は?

はこれまでのところ、私は次のことを試してみました:

var hexNumber string 
for idx := O; idx < 10000000; idx++ { 
    hexNumber = fmt.Sprintf("%04x", idx) 

    // Do some stuff .... 
} 

しかしfmt.Sprintfは非常に効率的ではありません。効率的にこれを達成するにはどうすればよいですか?

解決策:解決方法は@peterSO strconv.AppendIntです。

package bench 

import (
    "fmt" 
    "strconv" 
    "strings" 
    "testing" 
) 

var stringHex [16]string 
var runesHex [16]rune 

func init() { 
    stringHex = [16]string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"} 
    runesHex = [16]rune{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'} 
} 

func intToHex1(intNumber int) string { 
    hexNumber := []rune("0000") 
    for i, j := int(0), uint(12); i < 4; i, j = i+1, j-4 { 
     hexNumber[i] = runesHex[(intNumber>>j)&0x0f] 
    } 
    return string(hexNumber) 
} 

func intToHex2(intNumber int) string { 
    hexNumber := "0000" 
    for i, j := int(0), uint(12); i < 4; i, j = i+1, j-4 { 
     hexNumber = hexNumber[:i] + stringHex[(intNumber>>j)&0x0f] + hexNumber[i+1:] 
    } 
    return hexNumber 
} 

func BenchmarkFmtSprintf(b *testing.B) { 
    b.ReportAllocs() 
    for n := 0; n < b.N; n++ { 
     hexNumber := fmt.Sprintf("%04x", n) 
     _ = hexNumber 
    } 
} 

func BenchmarkStrconvFormatInt(b *testing.B) { 
    b.ReportAllocs() 
    for n := 0; n < b.N; n++ { 
     retStr := strings.Repeat("0", 4) + strconv.FormatInt(int64(n), 16) 
     hexNumber := retStr[(len(retStr) - 4):] 
     _ = hexNumber 
    } 
} 

func BenchmarkAppend(b *testing.B) { 
    b.ReportAllocs() 
    buf := []byte{'0', '0', '0', '0', 4 + 16: 0} 
    for n := 0; n < b.N; n++ { 
     buf = strconv.AppendInt(buf[:4], int64(n), 16) 
     hexNumber := string(buf[len(buf)-4:]) 
     _ = hexNumber 
    } 
} 

func BenchmarkIntToHex1(b *testing.B) { 
    b.ReportAllocs() 
    for n := 0; n < b.N; n++ { 
     hexNumber := intToHex1(n) 
     _ = hexNumber 
    } 
} 

func BenchmarkIntToHex2(b *testing.B) { 
    b.ReportAllocs() 
    for n := 0; n < b.N; n++ { 
     hexNumber := intToHex2(n) 
     _ = hexNumber 
    } 
} 

だから、ベンチマーク:

BenchmarkFmtSprintf-2   3000000    364 ns/op    16 B/op   2 allocs/op 
BenchmarkStrconvFormatInt-2  5000000    354 ns/op    15 B/op   3 allocs/op 
BenchmarkAppend-2    20000000    75.6 ns/op    0 B/op   0 allocs/op 
BenchmarkIntToHex1-2   10000000    162 ns/op    8 B/op   1 allocs/op 
BenchmarkIntToHex2-2    3000000    536 ns/op    16 B/op   4 allocs/op 
+0

あなたは、[0000、0xFFFFの] 'の'は 'に 'N'または 'S'の値をクランプすべきですfmt.Sprintf( "%04x"、n) '。それ以外の場合は、 'b.N> 0xFFFF'(65,535)のときに16進数が多すぎます。たとえば、 'n:= 0x7FFFF; s:= fmt.Sprintf( "%04x"、n) '、' s'は '7ffff'、5桁の16進数:https://play.golang.org/p/hX4R1aocIJ。 Appendのさらに高速版である私の改訂版の回答を見てください。 – peterSO

答えて

2

strconv.AppendUintは、fmt.Sprintfより速いようです。例えば、

hex_test.go

package main 

import (
    "fmt" 
    "strconv" 
    "testing" 
) 

func BenchmarkFmtSprintf(b *testing.B) { 
    b.ReportAllocs() 
    for n := 0; n < b.N; n++ { 
     hexNumber := fmt.Sprintf("%04x", n&0xFFFF) 
     _ = hexNumber 
    } 
} 

func BenchmarkAppend(b *testing.B) { 
    b.ReportAllocs() 
    for n := 0; n < b.N; n++ { 
     buf := []byte{'0', '0', '0', 3 + 4: 0} 
     buf = strconv.AppendUint(buf[:3], uint64(n)&0xFFFF, 16) 
     hexNumber := string(buf[len(buf)-4:]) 
     _ = hexNumber // Do some stuff .... 
    } 
} 

出力:=:

$ go test -bench=. hex_test.go 
BenchmarkSprintf-4  10000000  116 ns/op  16 B/op  1 allocs/op 
BenchmarkAppend-4  100000000  19.2 ns/op  0 B/op  0 allocs/op 
+0

さらに高速なバージョンに更新されました。 – peterSO

0

手動そしてちょうどパッド、のStrConvを使用することができるはずです。これはおそらく動作しません。

strconv.FormatInt(idx,16) 
関連する問題