Why is big(0.5) printed as 0.50?

I’m not sure if this is the intended behavior:

julia> 0.5
0.5

julia> big(0.5)
0.50

julia> big(0.5) == 0.5
true

Why the extra 0 at the end for a BigFloat?

Output is done by the show function which is different for the two types:

julia> @which show(stdout,big(0.5))
show(io::IO, b::BigFloat) in Base.MPFR at mpfr.jl:1002

julia> @which show(stdout,0.5)
show(io::IO, x::T) where T<:Union{Float16, Float32, Float64} in Base.Ryu at ryu\Ryu.jl:111

This is show for BigFloat:

function show(io::IO, b::BigFloat)
    if get(io, :compact, false)
        print(io, _string(b, 5))
    else
        print(io, _string(b))
    end
end

And this for standard Float64:

function Base.show(io::IO, x::T, forceuntyped::Bool=false, fromprint::Bool=false) where {T <: Base.IEEEFloat}
    compact = get(io, :compact, false)::Bool
    buf = Base.StringVector(neededdigits(T))
    typed = !forceuntyped && !compact && get(io, :typeinfo, Any) != typeof(x)
    pos = writeshortest(buf, 1, x, false, false, true, -1,
        (x isa Float32 && !fromprint) ? UInt8('f') : UInt8('e'), false, UInt8('.'), typed, compact)
    write(io, resize!(buf, pos - 1))
    return
end

I didn’t checked now for the specific additional 0 in the bigFloat case, but you can play around with both implementations to explore the differences.

1 Like

For the bigFloat you also need (from the same file):

function _string(x::BigFloat, fmt::String)::String
    isfinite(x) || return string(Float64(x))
    _prettify_bigfloat(string_mpfr(x, fmt))
end
_string(x::BigFloat) = _string(x, "%.Re")
_string(x::BigFloat, k::Integer) = _string(x, "%.$(k)Re")

string(b::BigFloat) = _string(b)

print(io::IO, b::BigFloat) = print(io, string(b))

but you can open those files on your own to get all needed dependencies, like
_prettify_bigfloat(s::String)::String

I realize that the methods are different, but my question was if this behavior is intended or if it is a bug in the display format.

3 Likes

I don’t know, probably not intended that there is some special reasoning behind it. But that doesn’t make it a bug. I would say: it’s not important enough to deal with it in a priorized way.

1 Like

The string is rendered by MPFR as “5.0e-1”. Julia gets rid of the “e” notation by moving the decimal point.

6 Likes

For convenience/reference, the code that does that is here:

function _prettify_bigfloat(s::String)::String
    mantissa, exponent = split(s, 'e')
    if !occursin('.', mantissa)
        mantissa = string(mantissa, '.')
    end
    mantissa = rstrip(mantissa, '0')
    if endswith(mantissa, '.')
        mantissa = string(mantissa, '0')
    end
    expo = parse(Int, exponent)
    if -5 < expo < 6
        expo == 0 && return mantissa
        int, frac = split(mantissa, '.')
        if expo > 0
            expo < length(frac) ?
                string(int, frac[1:expo], '.', frac[expo+1:end]) :
                string(int, frac, '0'^(expo-length(frac)), '.', '0')
        else
            neg = startswith(int, '-')
            neg == true && (int = lstrip(int, '-'))
            @assert length(int) == 1
            string(neg ? '-' : "", '0', '.', '0'^(-expo-1), int, frac)
        end
    else
        string(mantissa, 'e', exponent)
    end
end

From a brief study of this code, it seems like the line

string(neg ? '-' : "", '0', '.', '0'^(-expo-1), int, frac)

…could be tweaked to not include frac if it is zero, as is the case with 0.5.

Maybe that behavior is there for a reason, but I guess I could submit a PR and see what feedback I get.

Update: I’ve submitted a PR: mpfr.jl: don't add extra zero when pretty-printing BigFloats by waldyrious · Pull Request #40513 · JuliaLang/julia · GitHub

5 Likes