如何将一个数字类型的切片转换为另一个类型

时间:2014-11-16 13:42:58

标签: go

我尝试使用Go语言并且对它很陌生。我已经成功完成了这些教程,现在正在编写一个小程序来评估我通常所做的操作类型的性能。我有一个很长的float32类型的片段,需要尽可能高效地将它转换为float64类型的片。除了遍历切片的元素并通过output [i] = float64(data [i])显式转换单个元素的类型之外,是否有方法可以用来转换整个切片而无需迭代?我尝试过搜索解决方案,但没有发现任何直接相关的内容。

2 个答案:

答案 0 :(得分:2)

Go非常低级,这意味着迭代切片最有效的方法。其他语言可能有这样的内置函数,但他们所做的只是遍历切片,没有迭代就没有办法做到这一点。但是有一些技巧,特别是使用范围并避免索引切片,因为在越界检查中存在开销。这将是最有效的:

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)

请注意,在范围循环中使用:=将是低效的,因为在当前版本的Go中,变量被抛弃并且每次都重新创建而不是被重用。使用range代替for i=0; i<n; i++会更有效,因为它会在ar上保存边界检查。

答案 1 :(得分:2)

对性能声明持怀疑态度总是明智的。例如,&#34;在范围循环中使用:=将是低效的,因为......变量被抛弃并且每次都重新创建而不是被重用。&#34;

让我们看看连续三次运行的基准测试结果。

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
$