runtime: use dedicated printfloat32

It can be unexpected that printing a float32 involves 64-bit floating
point routines, see for example:
https://github.com/tinygo-org/tinygo/issues/1415

This commit adds a dedicated printfloat32 instead just for printing
float32 values. It comes with a possible code size increase, but only if
both float32 and float64 values are printed. Therefore, this should be
an improvement in almost all cases.

I also tried using printfloat32 for everything (and casting a float64 to
float32 to print) but the printed values are slightly different,
breaking the testdata/math.go test for example.
Этот коммит содержится в:
Ayke van Laethem 2020-09-27 14:26:09 +02:00 коммит произвёл Ron Evans
родитель 67de8b490d
коммит 431e51b8a0
3 изменённых файлов: 87 добавлений и 3 удалений

Просмотреть файл

@ -98,10 +98,90 @@ func printint64(n int64) {
printuint64(uint64(n)) printuint64(uint64(n))
} }
// printfloat32() was copied from the relevant source in the original Go
// implementation and modified to work with float32 instead of float64. It is
// copyright by the Go authors, licensed under the same BSD 3-clause license.
// See https://golang.org/LICENSE for details.
//
// It is a near-duplicate of printfloat64. This is done so that printing a
// float32 value doesn't involve float64 routines, which can be unexpected and a
// problem sometimes. It comes with a possible code size reduction if both
// printfloat32 and printfloat64 are used, which seems uncommon.
//
// Source:
// https://github.com/golang/go/blob/master/src/runtime/print.go
func printfloat32(v float32) { func printfloat32(v float32) {
// TODO: write an implementation like printfloat64, as some systems have switch {
// 32-bit floats but only software emulation for 64-bit floats. case v != v:
printfloat64(float64(v)) printstring("NaN")
return
case v+v == v && v > 0:
printstring("+Inf")
return
case v+v == v && v < 0:
printstring("-Inf")
return
}
const n = 7 // digits printed
var buf [n + 7]byte
buf[0] = '+'
e := 0 // exp
if v == 0 {
if 1/v < 0 {
buf[0] = '-'
}
} else {
if v < 0 {
v = -v
buf[0] = '-'
}
// normalize
for v >= 10 {
e++
v /= 10
}
for v < 1 {
e--
v *= 10
}
// round
h := float32(5.0)
for i := 0; i < n; i++ {
h /= 10
}
v += h
if v >= 10 {
e++
v /= 10
}
}
// format +d.dddd+edd
for i := 0; i < n; i++ {
s := int(v)
buf[i+2] = byte(s + '0')
v -= float32(s)
v *= 10
}
buf[1] = buf[2]
buf[2] = '.'
buf[n+2] = 'e'
buf[n+3] = '+'
if e < 0 {
e = -e
buf[n+3] = '-'
}
buf[n+4] = byte(e/100) + '0'
buf[n+5] = byte(e/10)%10 + '0'
buf[n+6] = byte(e%10) + '0'
for _, c := range buf {
putchar(c)
}
} }
// printfloat64() was copied from the relevant source in the original Go // printfloat64() was copied from the relevant source in the original Go

3
testdata/print.go предоставленный
Просмотреть файл

@ -29,6 +29,9 @@ func main() {
// print float64 // print float64
println(3.14) println(3.14)
// print float32
println(float32(3.14))
// print complex128 // print complex128
println(5 + 1.2345i) println(5 + 1.2345i)

1
testdata/print.txt предоставленный
Просмотреть файл

@ -16,6 +16,7 @@ a b c
123456789012 123456789012
-123456789012 -123456789012
+3.140000e+000 +3.140000e+000
+3.140000e+000
(+5.000000e+000+1.234500e+000i) (+5.000000e+000+1.234500e+000i)
(0:nil) (0:nil)
map[2] map[2]