Skip to content

Commit 75ec2b9

Browse files
Merge pull request #23388 from jw3126/big
Make printing of big(NaN) consistent #23382
2 parents d11a235 + 7d60a81 commit 75ec2b9

File tree

3 files changed

+96
-33
lines changed

3 files changed

+96
-33
lines changed

base/mpfr.jl

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -894,30 +894,63 @@ end
894894

895895
setprecision(f::Function, precision::Integer) = setprecision(f, BigFloat, precision)
896896

897-
function string(x::BigFloat)
898-
if isnan(x) || isinf(x)
899-
return string("BigFloat(", Float64(x), ", ", precision(x), ")")
897+
function string_mpfr(x::BigFloat, fmt::String)
898+
buf = Base.StringVector(0)
899+
s = _calculate_buffer_size!(buf, fmt, x)
900+
resize!(buf, s)
901+
_fill_buffer!(buf, fmt, x)
902+
String(buf)
903+
end
904+
905+
function _calculate_buffer_size!(buf, fmt, x::BigFloat)
906+
ccall((:mpfr_snprintf,:libmpfr),
907+
Int32, (Ptr{UInt8}, Culong, Ptr{UInt8}, Ptr{BigFloat}...),
908+
buf, 0, fmt, &x)
909+
end
910+
911+
function _fill_buffer!(buf, fmt, x::BigFloat)
912+
s = length(buf)
913+
# we temporarily need one more item in buffer to capture null termination
914+
resize!(buf, s + 1)
915+
n = ccall((:mpfr_sprintf,:libmpfr), Int32, (Ptr{UInt8}, Ptr{UInt8}, Ptr{BigFloat}...), buf, fmt, &x)
916+
@assert n + 1 == length(buf)
917+
@assert last(buf) == 0x00
918+
resize!(buf, s)
919+
end
920+
921+
function _prettify_bigfloat(s::String)::String
922+
mantissa, exponent = split(s, 'e')
923+
if !contains(mantissa, '.')
924+
mantissa = string(mantissa, '.')
900925
end
901-
902-
# In general, the number of decimal places needed to read back the number exactly
903-
# is, excluding the most significant, ceil(log(10, 2^precision(x)))
904-
k = ceil(Int32, precision(x) * 0.3010299956639812)
905-
lng = k + Int32(8) # Add space for the sign, the most significand digit, the dot and the exponent
906-
buf = Base.StringVector(lng + 1)
907-
# format strings are guaranteed to contain no NUL, so we don't use Cstring
908-
lng = ccall((:mpfr_snprintf,:libmpfr), Int32, (Ptr{UInt8}, Culong, Ptr{UInt8}, Ref{BigFloat}...), buf, lng + 1, "%.Re", x)
909-
if lng < k + 5 # print at least k decimal places
910-
lng = ccall((:mpfr_sprintf,:libmpfr), Int32, (Ptr{UInt8}, Ptr{UInt8}, Ref{BigFloat}...), buf, "%.$(k)Re", x)
911-
elseif lng > k + 8
912-
buf = Base.StringVector(lng + 1)
913-
lng = ccall((:mpfr_snprintf,:libmpfr), Int32, (Ptr{UInt8}, Culong, Ptr{UInt8}, Ref{BigFloat}...), buf, lng + 1, "%.Re", x)
926+
mantissa = rstrip(mantissa, '0')
927+
if endswith(mantissa, '.')
928+
mantissa = string(mantissa, '0')
929+
end
930+
if exponent == "+00"
931+
mantissa
932+
else
933+
string(mantissa, 'e', exponent)
914934
end
915-
n = (1 <= x < 10 || -10 < x <= -1 || iszero(x)) ? lng - 4 : lng
916-
return String(resize!(buf,n))
917935
end
918936

937+
function _string(x::BigFloat, fmt::String)::String
938+
isfinite(x) || return string(Float64(x))
939+
_prettify_bigfloat(string_mpfr(x, fmt))
940+
end
941+
_string(x::BigFloat) = _string(x, "%.Re")
942+
_string(x::BigFloat, k::Integer) = _string(x, "%.$(k)Re")
943+
944+
string(b::BigFloat) = _string(b)
945+
919946
print(io::IO, b::BigFloat) = print(io, string(b))
920-
show(io::IO, b::BigFloat) = print(io, string(b))
947+
function show(io::IO, b::BigFloat)
948+
if get(io, :compact, false)
949+
print(io, _string(b, 5))
950+
else
951+
print(io, _string(b))
952+
end
953+
end
921954

922955
# get/set exponent min/max
923956
get_emax() = ccall((:mpfr_get_emax, :libmpfr), Clong, ())

test/mpfr.jl

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -382,17 +382,14 @@ setprecision(406) do
382382
@test string(nextfloat(BigFloat(1))) == str
383383
end
384384
setprecision(21) do
385-
@test string(zero(BigFloat)) == "0.0000000"
386385
@test string(parse(BigFloat, "0.1")) == "1.0000002e-01"
387386
@test string(parse(BigFloat, "-9.9")) == "-9.9000015"
388387
end
389388
setprecision(40) do
390-
@test string(zero(BigFloat)) == "0.0000000000000"
391389
@test string(parse(BigFloat, "0.1")) == "1.0000000000002e-01"
392390
@test string(parse(BigFloat, "-9.9")) == "-9.8999999999942"
393391
end
394392
setprecision(123) do
395-
@test string(zero(BigFloat)) == "0.00000000000000000000000000000000000000"
396393
@test string(parse(BigFloat, "0.1")) == "9.99999999999999999999999999999999999953e-02"
397394
@test string(parse(BigFloat, "-9.9")) == "-9.8999999999999999999999999999999999997"
398395
end
@@ -880,15 +877,43 @@ for prec in (10, 100, 1000)
880877
end
881878
end
882879

883-
setprecision(256) do
884-
@test string(big(Inf)) == "BigFloat(Inf, 256)"
885-
@test string(big(-Inf)) == "BigFloat(-Inf, 256)"
886-
@test string(big(NaN)) == "BigFloat(NaN, 256)"
887-
end
888-
889880
# issue #22758
890881
if MPFR.version() > v"3.1.5" || "r11590" in MPFR.version().build
891882
setprecision(2_000_000) do
892883
@test abs(sin(big(pi)/6) - 0.5) < ldexp(big(1.0),-1_999_000)
893884
end
894885
end
886+
887+
@testset "show BigFloat" begin
888+
function test_show_bigfloat(x::BigFloat; contains_e::Bool=true,
889+
ends::String="",
890+
starts::String="")
891+
sx = sprint(show, x)
892+
scx = sprint(showcompact, x)
893+
strx = string(x)
894+
@test sx == strx
895+
@test length(scx) < 20
896+
@test length(scx) <= length(sx)
897+
@test x == parse(BigFloat, sx)
898+
@test (x, parse(BigFloat, scx), rtol=1e-4)
899+
for s in (sx, scx)
900+
@test contains(s, 'e') == contains_e
901+
@test startswith(s, starts)
902+
@test endswith(s, ends)
903+
end
904+
end
905+
906+
test_show_bigfloat(big"1.23456789", contains_e=false, starts="1.23")
907+
test_show_bigfloat(big"-1.23456789", contains_e=false, starts="-1.23")
908+
test_show_bigfloat(big"2.3457645687563543266576889678956787e10000", starts="2.345", ends="e+10000")
909+
test_show_bigfloat(big"-2.3457645687563543266576889678956787e-10000", starts="-2.345", ends="e-10000")
910+
911+
for to_string in [string,
912+
x->sprint(show, x),
913+
x->sprint(showcompact,x)]
914+
@test to_string(big"0.0") == "0.0"
915+
@test to_string(big"-0.0") == "-0.0"
916+
@test to_string(big"1.0") == "1.0"
917+
@test to_string(big"-1.0") == "-1.0"
918+
end
919+
end

test/numbers.jl

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3029,9 +3029,14 @@ end
30293029
end
30303030
end
30313031

3032-
@testset "compact NaN printing" begin
3033-
@test sprint(io->show(IOContext(io, :compact => true), NaN16)) == "NaN"
3034-
@test sprint(io->show(IOContext(io, :compact => true), NaN32)) == "NaN"
3035-
@test sprint(io->show(IOContext(io, :compact => true), NaN64)) == "NaN"
3036-
@test_broken sprint(io->show(IOContext(io, :compact => true), big(NaN))) == "NaN"
3032+
@testset "printing non finite floats" for T in subtypes(AbstractFloat)
3033+
for (x, sx) in [(T(NaN), "NaN"),
3034+
(-T(NaN), "NaN"),
3035+
(T(Inf), "Inf"),
3036+
(-T(Inf), "-Inf")]
3037+
@assert x isa T
3038+
@test string(x) == sx
3039+
@test sprint(io -> show(IOContext(io, :compact => true), x)) == sx
3040+
@test sprint(print, x) == sx
3041+
end
30373042
end

0 commit comments

Comments
 (0)