diff --git a/REQUIRE b/REQUIRE index 2573b15..5ddb4fa 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1,3 +1,3 @@ julia 0.6 -Compat 0.46.0 +Compat 0.53.0 BinDeps diff --git a/src/DecFP.jl b/src/DecFP.jl index cbb22d6..7628dd6 100644 --- a/src/DecFP.jl +++ b/src/DecFP.jl @@ -3,6 +3,23 @@ module DecFP using Compat, Compat.Printf, Compat.Unicode +# When Compat PR #491 is merged, REQUIRE that version and delete this +# 0.7.0-DEV.3469 +@static if !isdefined(Base, :GC) + @eval module GC + using Base: gc + const enable = Base.gc_enable + @static if !isdefined(Base, Symbol("@gc_preserve")) + macro preserve(args...) + esc(args[end]) + end + else + @eval const $(Symbol("@preserve")) = Base.$(Symbol("@gc_preserve")) + end + end + export GC +end + export Dec32, Dec64, Dec128, @d_str, @d32_str, @d64_str, @d128_str const libbid = joinpath(dirname(@__FILE__), "..", "deps", "libbid$(Sys.WORD_SIZE)") @@ -71,14 +88,6 @@ function isnanstr(s::AbstractString) return true end -function Base.show(io::IO, x::DecimalFloatingPoint) - s = @sprintf("%g", x) - if contains(s, r"^-?\d+$") - s *= ".0" - end - print(io, s) -end - for w in (32,64,128) BID = Symbol(string("Dec",w)) Ti = eval(Symbol(string("UInt",w))) @@ -105,6 +114,62 @@ for w in (32,64,128) $BID(x::AbstractString) = parse($BID, x) + function Base.show(io::IO, x::$BID) + isnan(x) && (write(io, "NaN"); return) + isinf(x) && (write(io, signbit(x) ? "-Inf" : "Inf"); return) + x == 0 && (write(io, signbit(x) ? "-0.0" : "0.0"); return) + ccall(($(bidsym(w,"to_string")), libbid), Cvoid, (Ptr{UInt8}, $BID), _buffer, x) + if _buffer[1] == UInt8('-') + write(io, '-') + end + normalized_exponent = nox(ccall(($(bidsym(w,"ilogb")), libbid), Cint, ($BID,), x)) + lastdigitindex = Compat.findfirst(equalto(UInt8('E')), _buffer) - 1 + lastnonzeroindex = Compat.findlast(!equalto(UInt8('0')), view(_buffer, 1:lastdigitindex)) + if -5 < normalized_exponent < 6 + # %f + if normalized_exponent >= 0 + if normalized_exponent >= lastnonzeroindex - 2 + GC.@preserve _buffer unsafe_write(io, pointer(_buffer, 2), lastnonzeroindex - 1) + writezeros(io, normalized_exponent - lastnonzeroindex + 2) + write(io, ".0") + else + GC.@preserve _buffer unsafe_write(io, pointer(_buffer, 2), normalized_exponent + 1) + write(io, '.') + GC.@preserve _buffer unsafe_write(io, pointer(_buffer, normalized_exponent + 3), lastnonzeroindex - normalized_exponent - 2) + end + else + write(io, "0.") + writezeros(io, -normalized_exponent - 1) + GC.@preserve _buffer unsafe_write(io, pointer(_buffer, 2), lastnonzeroindex - 1) + end + else + # %e + write(io, _buffer[2], '.') + if lastnonzeroindex == 2 + write(io, '0') + else + GC.@preserve _buffer unsafe_write(io, pointer(_buffer, 3), lastnonzeroindex - 2) + end + write(io, 'e') + if normalized_exponent < 0 + write(io, '-') + normalized_exponent = -normalized_exponent + end + b_lb = div(normalized_exponent, 10) + b = 1 + while b <= b_lb + b *= 10 + end + r = normalized_exponent + while b > 0 + q, r = divrem(r, b) + write(io, UInt8('0') + (q%UInt8)) + b = div(b, 10) + end + end + return + end + function Base.Printf.fix_dec(x::$BID, n::Int) if n > length(DIGITS) - 1 n = length(DIGITS) - 1 @@ -369,4 +434,10 @@ function xchk(x, exc::Type{E}, args...; mask::Integer=0x3f) where {E<:Exception} return x end +function writezeros(io::IO, n::Int) + for i = 1:n + write(io, UInt8('0')) + end +end + end # module diff --git a/test/runtests.jl b/test/runtests.jl index e580fc6..a54f5d1 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -42,6 +42,25 @@ for T in (Dec32, Dec64, Dec128) @test parse(T, "0.1")::T == T(1//10) @test T("0.1")::T == T(1//10) + io = IOBuffer() + show(io, T("NaN")); @test String(take!(io)) == "NaN" + show(io, T("Inf")); @test String(take!(io)) == "Inf" + show(io, T("-Inf")); @test String(take!(io)) == "-Inf" + show(io, T("0")); @test String(take!(io)) == "0.0" + show(io, T("-0")); @test String(take!(io)) == "-0.0" + show(io, T("1")); @test String(take!(io)) == "1.0" + show(io, T("-1")); @test String(take!(io)) == "-1.0" + show(io, T("1.000")); @test String(take!(io)) == "1.0" + show(io, T("1e5")); @test String(take!(io)) == "100000.0" + show(io, T("1e6")); @test String(take!(io)) == "1.0e6" + show(io, T("1.23456e6")); @test String(take!(io)) == "1.23456e6" + show(io, T("1e-1")); @test String(take!(io)) == "0.1" + show(io, T("1e-4")); @test String(take!(io)) == "0.0001" + show(io, T("1e-5")); @test String(take!(io)) == "1.0e-5" + show(io, T("1.20e3")); @test String(take!(io)) == "1200.0" + show(io, T("123.456")); @test String(take!(io)) == "123.456" + show(io, T("0.00123456")); @test String(take!(io)) == "0.00123456" + # some Dec128 tests fail due to Issue #47 if T != Dec128 @test @sprintf("%7.2f", T("1.2345")) == " 1.23"