Skip to content

Commit 31e405f

Browse files
quinnjKristofferC
authored andcommitted
Fix rounding cases for fixed-width printing in ryu routines
Fixes #40303. When printing values to fixed widths through the `Ryu.writefixed` or `Ryu.writeexp` routines, we have a "cleanup" section after a value has been printed to see if it needs to be rounded given the input precision and width. The core issue was the terminating condition: it previously only checked if we were at the start of a buffer or had encountered the `'-'` character. Via Printf formatting, however, it also allows specifying the `'+'` and `' '` characters to preceed a formatted number. Hence, in the OP, the `'1'` character was getting "rounded" up to the `','` character. The fix here is correctly checking if the `plus` or `space` options were passed to the routine and if so, include those in our rounding termination check. The original issue only reported the "plus" case for the `f` format specifier, but the same bug affects the `e` format specifier and the "space" option. (cherry picked from commit fcf6779)
1 parent 7369d40 commit 31e405f

File tree

3 files changed

+10
-2
lines changed

3 files changed

+10
-2
lines changed

base/ryu/exp.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@
213213
roundPos = pos
214214
while true
215215
roundPos -= 1
216-
if roundPos == (startpos - 1) || buf[roundPos] == UInt8('-')
216+
if roundPos == (startpos - 1) || buf[roundPos] == UInt8('-') || (plus && buf[roundPos] == UInt8('+')) || (space && buf[roundPos] == UInt8(' '))
217217
buf[roundPos + 1] = UInt8('1')
218218
e += 1
219219
break

base/ryu/fixed.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@
166166
dotPos = 1
167167
while true
168168
roundPos -= 1
169-
if roundPos == (startpos - 1) || (buf[roundPos] == UInt8('-'))
169+
if roundPos == (startpos - 1) || (buf[roundPos] == UInt8('-')) || (plus && buf[roundPos] == UInt8('+')) || (space && buf[roundPos] == UInt8(' '))
170170
buf[roundPos + 1] = UInt8('1')
171171
if dotPos > 1
172172
buf[dotPos] = UInt8('0')

stdlib/Printf/test/runtests.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ end
141141
@test Printf.@sprintf("%+ 09.1f", 1.234) == "+000001.2"
142142
@test Printf.@sprintf("%+ 09.0f", 1.234) == "+00000001"
143143
@test Printf.@sprintf("%+ #09.0f", 1.234) == "+0000001."
144+
145+
#40303
146+
@test Printf.@sprintf("%+7.1f", 9.96) == " +10.0"
147+
@test Printf.@sprintf("% 7.1f", 9.96) == " 10.0"
144148
end
145149

146150
@testset "%e" begin
@@ -202,6 +206,10 @@ end
202206
@test Printf.@sprintf("%+ 09.1e", 1.234) == "+01.2e+00"
203207
@test Printf.@sprintf("%+ 09.0e", 1.234) == "+0001e+00"
204208
@test Printf.@sprintf("%+ #09.0e", 1.234) == "+001.e+00"
209+
210+
#40303
211+
@test Printf.@sprintf("%+9.1e", 9.96) == " +1.0e+01"
212+
@test Printf.@sprintf("% 9.1e", 9.96) == " 1.0e+01"
205213
end
206214

207215
@testset "strings" begin

0 commit comments

Comments
 (0)