Skip to content

Instantly share code, notes, and snippets.

@johnaoss
Last active September 28, 2019 22:13
Show Gist options
  • Save johnaoss/c9922003aa471609db08d07273049536 to your computer and use it in GitHub Desktop.
Save johnaoss/c9922003aa471609db08d07273049536 to your computer and use it in GitHub Desktop.
Float64->String Conversions in Go
package vals
import (
"strings"
"strconv"
"fmt"
)
// SprintValues is a set of float64 values that implements Buckets.
type SprintValues []float64
func (v SprintValues) String() string {
values := make([]string, len(v))
for i := range values {
values[i] = fmt.Sprintf("%f", v[i])
}
return fmt.Sprint(values)
}
type ConvValues []float64
func (v ConvValues) String() string {
values := make([]string, len(v))
for i := range values {
values[i] = strconv.FormatFloat(v[i], 'f', 6, 64) // matches fmt formatting
}
return fmt.Sprint(values)
}
type BuildValues []float64
func (v BuildValues) String() string {
var b strings.Builder
b.WriteByte('[')
for i := range v {
fmt.Fprintf(&b, "%f", v[i])
if i != len(v)-1{
b.WriteByte(' ')
}
}
b.WriteByte(']')
return b.String()
}
package vals
import (
"runtime"
"testing"
)
var sortArr []float64
func init() {
sortArr = []float64{3.0,4.0,1.0,4.0,12.0,99999.000000001, 99999999.000002002}
for i := 0; i < 16; i++ {
sortArr = append(sortArr, sortArr...)
}
}
func BenchmarkPrintf(b *testing.B) {
b.ReportAllocs()
bucket := SprintValues(sortArr)
for i := 0; i < b.N; i++ {
result := bucket.String()
runtime.KeepAlive(result)
}
}
func BenchmarkStrConv(b *testing.B) {
b.ReportAllocs()
bucket := ConvValues(sortArr)
for i := 0; i < b.N; i++ {
result := bucket.String()
runtime.KeepAlive(result)
}
}
func BenchmarkBuilder(b *testing.B) {
b.ReportAllocs()
bucket := BuildValues(sortArr)
for i := 0; i < b.N; i++ {
result := bucket.String()
runtime.KeepAlive(result)
}
}
func TestEquality(t *testing.T) {
build := BuildValues(sortArr)
val := SprintValues(sortArr)
conv := ConvValues(sortArr)
if build.String() != val.String() {
t.Errorf("%s::%s", build.String(), val.String())
}
if val.String() != conv.String() {
t.Errorf("%s::%s", val.String(), conv.String())
}
if conv.String() != build.String() {
t.Errorf("%s::%s", conv.String(), build.String())
}
t.Log("Builder:", build.String())
t.Log("Sprintf:", val.String())
t.Log("Strconv:", conv.String())
}
BenchmarkPrintf-8    	       6	 187680616 ns/op	57351464 B/op	 1376303 allocs/op
BenchmarkStrConv-8   	       7	 173820460 ns/op	68361486 B/op	 1376303 allocs/op
BenchmarkBuilder-8   	       9	 121909527 ns/op	32507531 B/op	  458804 allocs/op

Not an order of magnitude faster, but the allocation savings alone is worth switching to a strings.Builder if you can.

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