How to convert a slice from one number type to another type

I am experimenting with Go language and quite new to this. I successfully completed the tutorials, and now I am writing a small program to evaluate its performance for the type of operations that I usually do. I have a long piece of type float32 and need to convert it into a piece of type float64 as efficiently as possible. Besides repeating using slice elements and explicitly converting the types of individual elements through the output [i] = float64 (data [i]), is there a method that I can use to convert the entire fragment without the need for iteration? I tried to find a solution, but did not find anything directly related.

+4
source share
2 answers

Go is pretty low level, which means that iterating through a slice is the most efficient method. Other languages ​​may have built-in functions for such things, but all they do is iterate through a slice, there is no way to do this without iteration. But there are some tricks, in particular, to use the range and avoid slice indexing, as there is overhead in checking outside the limits. This would be most effective:

func convertTo64(ar []float32) []float64 {
   newar := make([]float64, len(ar))
   var v float32
   var i int
   for i, v = range ar {
      newar[i] = float64(v)
   }
   return newar
}

slice32 := make([]float32, 1000)
slice64 := convertTo64(slice32)

Note that using :=a range in a loop would be inefficient, because in the current version of Go, the variable is thrown out and recreated each time instead of being reused. Using rangeinstead is for i=0; i<n; i++more efficient because it keeps bounds bound on ar.

+2
source

. , ": = , ... ".

.

floats_test.go:

package main

import "testing"

var slice64 []float64

func FuncVar(f32 []float32) []float64 {
    f64 := make([]float64, len(f32))
    var f float32
    var i int
    for i, f = range f32 {
        f64[i] = float64(f)
    }
    return f64
}

func BenchmarkFuncVar(b *testing.B) {
    f32 := make([]float32, 1024)
    b.ReportAllocs()
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        slice64 = FuncVar(f32)
    }
}

func RangeVar(f32 []float32) []float64 {
    f64 := make([]float64, len(f32))
    for i, f := range f32 {
        f64[i] = float64(f)
    }
    return f64
}

func BenchmarkRangeVar(b *testing.B) {
    f32 := make([]float32, 1024)
    b.ReportAllocs()
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        slice64 = RangeVar(f32)
    }
}

func main() {}

:

$ go test -v -run=! -bench=.
testing: warning: no tests to run
PASS
BenchmarkFuncVar      100000         12260 ns/op        8192 B/op          1 allocs/op
BenchmarkRangeVar     100000         12125 ns/op        8192 B/op          1 allocs/op
ok      so/test 2.703s
$ go test -v -run=! -bench=.
testing: warning: no tests to run
PASS
BenchmarkFuncVar      100000         12620 ns/op        8192 B/op          1 allocs/op
BenchmarkRangeVar     100000         12623 ns/op        8192 B/op          1 allocs/op
ok      so/test 2.782s
$ go test -v -run=! -bench=.
testing: warning: no tests to run
PASS
BenchmarkFuncVar      100000         12730 ns/op        8192 B/op          1 allocs/op
BenchmarkRangeVar     100000         12971 ns/op        8192 B/op          1 allocs/op
ok      so/test 2.852s
$ 

, . , .

package main

import (
    "fmt"
    "time"
)

const N = 1e6

var f32 = make([]float32, 1024)
var slice64 []float64

func FuncVar(f32 []float32) []float64 {
    f64 := make([]float64, len(f32))
    var f float32
    var i int
    for i, f = range f32 {
        f64[i] = float64(f)
    }
    return f64
}

func BenchmarkFuncVar() {
    t1 := time.Now()
    for i := 0; i < N; i++ {
        slice64 = FuncVar(f32)
    }
    t2 := time.Now()
    fmt.Println("FuncVar", t2.Sub(t1))
}

func RangeVar(f32 []float32) []float64 {
    f64 := make([]float64, len(f32))
    for i, f := range f32 {
        f64[i] = float64(f)
    }
    return f64
}

func BenchmarkRangeVar() {
    t1 := time.Now()
    for i := 0; i < N; i++ {
        slice64 = RangeVar(f32)
    }
    t2 := time.Now()
    fmt.Println("RangeVar", t2.Sub(t1))
}

func main() {
    BenchmarkFuncVar()
    BenchmarkRangeVar()
}

:

$ go build floata.go && ./floata
FuncVar 10.479653966s
RangeVar 10.208178244s
$ go build floata.go && ./floata
FuncVar 10.123357283s
RangeVar 10.173007394s
$ go build floata.go && ./floata
FuncVar 9.935580721s
RangeVar 10.109644784s
$ go build floata.go && ./floata
FuncVar 10.070552761s
RangeVar 10.317730473s
$ go build floata.go && ./floata
FuncVar 10.075578601s
RangeVar 10.012273678s
$
+2

All Articles