Skip to content

Commit 431e51b

Browse files
aykevldeadprogram
authored andcommitted
runtime: use dedicated printfloat32
It can be unexpected that printing a float32 involves 64-bit floating point routines, see for example: #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.
1 parent 67de8b4 commit 431e51b

File tree

3 files changed

+87
-3
lines changed

3 files changed

+87
-3
lines changed

src/runtime/print.go

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,90 @@ func printint64(n int64) {
9898
printuint64(uint64(n))
9999
}
100100

101+
// printfloat32() was copied from the relevant source in the original Go
102+
// implementation and modified to work with float32 instead of float64. It is
103+
// copyright by the Go authors, licensed under the same BSD 3-clause license.
104+
// See https://golang.org/LICENSE for details.
105+
//
106+
// It is a near-duplicate of printfloat64. This is done so that printing a
107+
// float32 value doesn't involve float64 routines, which can be unexpected and a
108+
// problem sometimes. It comes with a possible code size reduction if both
109+
// printfloat32 and printfloat64 are used, which seems uncommon.
110+
//
111+
// Source:
112+
// https://github.com/golang/go/blob/master/src/runtime/print.go
101113
func printfloat32(v float32) {
102-
// TODO: write an implementation like printfloat64, as some systems have
103-
// 32-bit floats but only software emulation for 64-bit floats.
104-
printfloat64(float64(v))
114+
switch {
115+
case v != v:
116+
printstring("NaN")
117+
return
118+
case v+v == v && v > 0:
119+
printstring("+Inf")
120+
return
121+
case v+v == v && v < 0:
122+
printstring("-Inf")
123+
return
124+
}
125+
126+
const n = 7 // digits printed
127+
var buf [n + 7]byte
128+
buf[0] = '+'
129+
e := 0 // exp
130+
if v == 0 {
131+
if 1/v < 0 {
132+
buf[0] = '-'
133+
}
134+
} else {
135+
if v < 0 {
136+
v = -v
137+
buf[0] = '-'
138+
}
139+
140+
// normalize
141+
for v >= 10 {
142+
e++
143+
v /= 10
144+
}
145+
for v < 1 {
146+
e--
147+
v *= 10
148+
}
149+
150+
// round
151+
h := float32(5.0)
152+
for i := 0; i < n; i++ {
153+
h /= 10
154+
}
155+
v += h
156+
if v >= 10 {
157+
e++
158+
v /= 10
159+
}
160+
}
161+
162+
// format +d.dddd+edd
163+
for i := 0; i < n; i++ {
164+
s := int(v)
165+
buf[i+2] = byte(s + '0')
166+
v -= float32(s)
167+
v *= 10
168+
}
169+
buf[1] = buf[2]
170+
buf[2] = '.'
171+
172+
buf[n+2] = 'e'
173+
buf[n+3] = '+'
174+
if e < 0 {
175+
e = -e
176+
buf[n+3] = '-'
177+
}
178+
179+
buf[n+4] = byte(e/100) + '0'
180+
buf[n+5] = byte(e/10)%10 + '0'
181+
buf[n+6] = byte(e%10) + '0'
182+
for _, c := range buf {
183+
putchar(c)
184+
}
105185
}
106186

107187
// printfloat64() was copied from the relevant source in the original Go

testdata/print.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ func main() {
2929
// print float64
3030
println(3.14)
3131

32+
// print float32
33+
println(float32(3.14))
34+
3235
// print complex128
3336
println(5 + 1.2345i)
3437

testdata/print.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ a b c
1616
123456789012
1717
-123456789012
1818
+3.140000e+000
19+
+3.140000e+000
1920
(+5.000000e+000+1.234500e+000i)
2021
(0:nil)
2122
map[2]

0 commit comments

Comments
 (0)