У вас есть несколько ошибок в вашей логике, тесте и ваших предположениях.
Что касается приведения, ваши результаты показывают, что цикл for выполняется 1000 раз.Так как вы выполняете цикл 1M раз, это фактически делает 1 миллиард операций приведения ... не слишком потертый.
На самом деле, я немного переработал ваш код:
const (
min = float64(math.SmallestNonzeroFloat32)
max = float64(math.MaxFloat32)
)
func cast(in float64) (out float32, err error) {
// We need to guard here, as casting from float64 to float32 looses precision
// Therefor, we might get out of scope.
if in < min {
return 0.00, fmt.Errorf("%f is smaller than smallest float32 (%f)", in, min)
} else if in > max {
return 0.00, fmt.Errorf("%f is bigger than biggest float32 (%f)", in, max)
}
return float32(in), nil
}
// multi64 uses a variadic in parameter, in order to be able
// to use the multiplication with arbitrary length.
func multi64(in ...float64) (result float32, err error) {
// Necessary to set it to 1.00, since float64's null value is 0.00...
im := float64(1.00)
for _, v := range in {
im = im * v
}
// We only need to cast once.
// You DO want to make the calculation with the original precision and only
// want to do the casting ONCE. However, this should not be done here - but in the
// caller, as the caller knows on how to deal with special cases.
return cast(im)
}
// multi32 is a rather non-sensical wrapper, since the for loop
// could easily be done in the caller.
// It is only here for comparison purposes.
func multi32(in ...float32) (result float32) {
result = 1.00
for _, v := range in {
result = result * v
}
return result
}
// openFile is here for comparison to show that you can do
// a... fantastic metric ton of castings in comparison to IO ops.
func openFile() error {
f, err := os.Open("cast.go")
if err != nil {
return fmt.Errorf("Error opening file")
}
defer f.Close()
br := bufio.NewReader(f)
if _, _, err := br.ReadLine(); err != nil {
return fmt.Errorf("Error reading line: %s", err)
}
return nil
}
со следующим тестовым кодом
func init() {
rand.Seed(time.Now().UTC().UnixNano())
}
func BenchmarkCast(b *testing.B) {
b.StopTimer()
v := rand.Float64()
var err error
b.ResetTimer()
b.StartTimer()
for i := 0; i < b.N; i++ {
if _, err = cast(v); err != nil {
b.Fail()
}
}
}
func BenchmarkMulti32(b *testing.B) {
b.StopTimer()
vals := make([]float32, 10)
for i := 0; i < 10; i++ {
vals[i] = rand.Float32() * float32(i+1)
}
b.ResetTimer()
b.StartTimer()
for i := 0; i < b.N; i++ {
multi32(vals...)
}
}
func BenchmarkMulti64(b *testing.B) {
b.StopTimer()
vals := make([]float64, 10)
for i := 0; i < 10; i++ {
vals[i] = rand.Float64() * float64(i+1)
}
var err error
b.ResetTimer()
b.StartTimer()
for i := 0; i < b.N; i++ {
if _, err = multi64(vals...); err != nil {
b.Log(err)
b.Fail()
}
}
}
func BenchmarkOpenFile(b *testing.B) {
var err error
for i := 0; i < b.N; i++ {
if err = openFile(); err != nil {
b.Log(err)
b.Fail()
}
}
}
Вы получаете что-то вроде этого
BenchmarkCast-4 1000000000 2.42 ns/op
BenchmarkMulti32-4 300000000 5.04 ns/op
BenchmarkMulti64-4 200000000 8.19 ns/op
BenchmarkOpenFile-4 100000 19591 ns/op
Так что, даже с этим относительно глупым и неоптимизированным кодом, злоумышленник является эталоном openFile.
Теперь давайтемы рассматриваем это в перспективе.19,562 нс равняется 0,019562 миллисекундам.Средний человек может воспринимать латентность около 20 миллисекунд.Так что даже те 100 000 ( "сто тысяч" ) открытий файлов, чтения строк и закрытий файлов примерно в 1000 раз быстрее, чем может воспринять человек.
Приведение, по сравнению с этим, несколько на порядки быстрее - поэтому разыгрывайте все, что вам нравится, узким местом будет I / O.
Edit
Что оставляет вопрос, почему вы делаетене импортировать значения как float64 на первое место?