Skip to content

Commit

Permalink
Fix rounding cases for fixed-width printing in ryu routines
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
quinnj authored and KristofferC committed Apr 4, 2021
1 parent 27d412a commit 85d25a1
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 2 deletions.
2 changes: 1 addition & 1 deletion base/ryu/exp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@
roundPos = pos
while true
roundPos -= 1
if roundPos == (startpos - 1) || buf[roundPos] == UInt8('-')
if roundPos == (startpos - 1) || buf[roundPos] == UInt8('-') || (plus && buf[roundPos] == UInt8('+')) || (space && buf[roundPos] == UInt8(' '))
buf[roundPos + 1] = UInt8('1')
e += 1
break
Expand Down
2 changes: 1 addition & 1 deletion base/ryu/fixed.jl
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@
dotPos = 1
while true
roundPos -= 1
if roundPos == (startpos - 1) || (buf[roundPos] == UInt8('-'))
if roundPos == (startpos - 1) || (buf[roundPos] == UInt8('-')) || (plus && buf[roundPos] == UInt8('+')) || (space && buf[roundPos] == UInt8(' '))
buf[roundPos + 1] = UInt8('1')
if dotPos > 1
buf[dotPos] = UInt8('0')
Expand Down
8 changes: 8 additions & 0 deletions stdlib/Printf/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@ end
@test Printf.@sprintf("%+ 09.1f", 1.234) == "+000001.2"
@test Printf.@sprintf("%+ 09.0f", 1.234) == "+00000001"
@test Printf.@sprintf("%+ #09.0f", 1.234) == "+0000001."

#40303
@test Printf.@sprintf("%+7.1f", 9.96) == " +10.0"
@test Printf.@sprintf("% 7.1f", 9.96) == " 10.0"
end

@testset "%e" begin
Expand Down Expand Up @@ -202,6 +206,10 @@ end
@test Printf.@sprintf("%+ 09.1e", 1.234) == "+01.2e+00"
@test Printf.@sprintf("%+ 09.0e", 1.234) == "+0001e+00"
@test Printf.@sprintf("%+ #09.0e", 1.234) == "+001.e+00"

#40303
@test Printf.@sprintf("%+9.1e", 9.96) == " +1.0e+01"
@test Printf.@sprintf("% 9.1e", 9.96) == " 1.0e+01"
end

@testset "strings" begin
Expand Down

0 comments on commit 85d25a1

Please sign in to comment.