Skip to content

Commit

Permalink
More robust non-integer conversions for %d Printf specifier (JuliaLan…
Browse files Browse the repository at this point in the history
…g#37554)

* More robust non-integer conversions for %d Printf specifier

Fixes JuliaLang#37552. As pointed out by Jameson, the non-integer conversion code
for the `%d` specifier handling code wasn't super robust; I wasn't sure
how robust it really needed to be, since it seems a bit sketchy to me
for users to be relying on Printf conversion behavior of non-integers
with `%d` anyway; C even throws a really scary warning if you pass
non-integer for `%d`. But anyways, this isn't that much more machinery
and puts back support for printf formatting of `Rational` with `%d`
anyway. But a note to users, I'd strongly suggest doing your own
conversion, `trunc`, `round`, whatever yourself to ensure you fully
understand what's going on if you really need to use the `%d` with
non-integer arguments.

As for the issue reported, it's note quite as severe a use-case since
they're just trying to represent a _huge_ integer via `Float64`, which
seems decently reasonable.

* Add test for Rational
  • Loading branch information
quinnj committed Sep 13, 2020
1 parent 90f8b17 commit f2e70d9
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 2 deletions.
10 changes: 8 additions & 2 deletions stdlib/Printf/src/Printf.jl
Original file line number Diff line number Diff line change
Expand Up @@ -262,11 +262,17 @@ end
end

# integers
toint(x) = x
toint(x::Rational) = Integer(x)
toint(x::AbstractFloat) = x > typemax(Int128) ?
BigInt(round(x)) : x > typemax(Int64) ?
Int128(round(x)) : Int64(round(x))

@inline function fmt(buf, pos, arg, spec::Spec{T}) where {T <: Ints}
leftalign, plus, space, zero, hash, width, prec =
spec.leftalign, spec.plus, spec.space, spec.zero, spec.hash, spec.width, spec.precision
bs = base(T)
arg2 = arg isa AbstractFloat ? Integer(round(arg)) : arg
arg2 = toint(arg)
n = i = ndigits(arg2, base=bs, pad=1)
x, neg = arg2 < 0 ? (-arg2, true) : (arg2, false)
arglen = n + (neg || (plus | space)) +
Expand Down Expand Up @@ -675,7 +681,7 @@ function plength(f::Spec{T}, x) where {T <: Strings}
end

function plength(f::Spec{T}, x) where {T <: Ints}
x2 = x isa AbstractFloat ? Integer(round(x)) : x
x2 = toint(x)
return max(f.width, f.precision + ndigits(x2, base=base(T), pad=1) + 5)
end

Expand Down
4 changes: 4 additions & 0 deletions stdlib/Printf/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,10 @@ end
# 37539
@test @sprintf(" %.1e\n", 0.999) == " 1.0e+00\n"
@test @sprintf(" %.1f", 9.999) == " 10.0"

# 37552
@test @sprintf("%d", 1.0e100) == "10000000000000000159028911097599180468360808563945281389781327557747838772170381060813469985856815104"
@test @sprintf("%d", 3//1) == "3"
end

@testset "integers" begin
Expand Down

0 comments on commit f2e70d9

Please sign in to comment.