1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
module Ryu
import .Base: significand_bits, significand_mask, exponent_bits, exponent_mask, exponent_bias, exponent_max, uinttype
include("utils.jl")
include("shortest.jl")
include("fixed.jl")
include("exp.jl")
"""
Ryu.neededdigits(T)
Number of digits necessary to represent type `T` in fixed-precision decimal.
"""
neededdigits(::Type{Float64}) = 309 + 17
neededdigits(::Type{Float32}) = 39 + 9 + 2
neededdigits(::Type{Float16}) = 9 + 5 + 9
"""
Ryu.writeshortest(x, plus=false, space=false, hash=true, precision=-1, expchar=UInt8('e'), padexp=false, decchar=UInt8('.'), typed=false, compact=false)
Ryu.writeshortest(buf::Vector{UInt8}, pos::Int, x, args...)
Convert a float value `x` into its "shortest" decimal string, which can be parsed back to the same value.
This function allows achieving the `%g` printf format.
Note the 2nd method allows passing in a byte buffer and position directly; callers must ensure the buffer has sufficient room to hold the entire decimal string.
Various options for the output format include:
* `plus`: for positive `x`, prefix decimal string with a `'+'` character
* `space`: for positive `x`, prefix decimal string with a `' '` character; overridden if `plus=true`
* `hash`: whether the decimal point should be written, even if no additional digits are needed for precision
* `precision`: minimum number of digits to be included in the decimal string; extra `'0'` characters will be added for padding if necessary
* `expchar`: character to use exponent component in scientific notation
* `padexp`: whether two digits should always be written, even for single-digit exponents (e.g. `e+1` becomes `e+01`)
* `decchar`: decimal point character to be used
* `typed`: whether additional type information should be printed for `Float16` / `Float32`
* `compact`: output will be limited to 6 significant digits
"""
function writeshortest(x::T,
plus::Bool=false,
space::Bool=false,
hash::Bool=true,
precision::Integer=-1,
expchar::UInt8=UInt8('e'),
padexp::Bool=false,
decchar::UInt8=UInt8('.'),
typed::Bool=false,
compact::Bool=false) where {T <: Base.IEEEFloat}
buf = Base.StringVector(neededdigits(T))
pos = writeshortest(buf, 1, x, plus, space, hash, precision, expchar, padexp, decchar, typed, compact)
return String(resize!(buf, pos - 1))
end
"""
Ryu.writefixed(x, precision, plus=false, space=false, hash=false, decchar=UInt8('.'), trimtrailingzeros=false)
Ryu.writefixed(buf::Vector{UInt8}, pos::Int, x, args...)
Convert a float value `x` into a "fixed" size decimal string of the provided precision.
This function allows achieving the `%f` printf format.
Note the 2nd method allows passing in a byte buffer and position directly; callers must ensure the buffer has sufficient room to hold the entire decimal string.
Various options for the output format include:
* `plus`: for positive `x`, prefix decimal string with a `'+'` character
* `space`: for positive `x`, prefix decimal string with a `' '` character; overridden if `plus=true`
* `hash`: whether the decimal point should be written, even if no additional digits are needed for precision
* `precision`: minimum number of significant digits to be included in the decimal string; extra `'0'` characters will be added for padding if necessary
* `decchar`: decimal point character to be used
* `trimtrailingzeros`: whether trailing zeros should be removed
"""
function writefixed(x::T,
precision::Integer,
plus::Bool=false,
space::Bool=false,
hash::Bool=false,
decchar::UInt8=UInt8('.'),
trimtrailingzeros::Bool=false) where {T <: Base.IEEEFloat}
buf = Base.StringVector(precision + neededdigits(T))
pos = writefixed(buf, 1, x, precision, plus, space, hash, decchar, trimtrailingzeros)
return String(resize!(buf, pos - 1))
end
"""
Ryu.writeexp(x, precision, plus=false, space=false, hash=false, expchar=UInt8('e'), decchar=UInt8('.'), trimtrailingzeros=false)
Ryu.writeexp(buf::Vector{UInt8}, pos::Int, x, args...)
Convert a float value `x` into a scientific notation decimal string.
This function allows achieving the `%e` printf format.
Note the 2nd method allows passing in a byte buffer and position directly; callers must ensure the buffer has sufficient room to hold the entire decimal string.
Various options for the output format include:
* `plus`: for positive `x`, prefix decimal string with a `'+'` character
* `space`: for positive `x`, prefix decimal string with a `' '` character; overridden if `plus=true`
* `hash`: whether the decimal point should be written, even if no additional digits are needed for precision
* `precision`: minimum number of significant digits to be included in the decimal string; extra `'0'` characters will be added for padding if necessary
* `expchar`: character to use exponent component in scientific notation
* `decchar`: decimal point character to be used
* `trimtrailingzeros`: whether trailing zeros should be removed
"""
function writeexp(x::T,
precision::Integer,
plus::Bool=false,
space::Bool=false,
hash::Bool=false,
expchar::UInt8=UInt8('e'),
decchar::UInt8=UInt8('.'),
trimtrailingzeros::Bool=false) where {T <: Base.IEEEFloat}
buf = Base.StringVector(precision + neededdigits(T))
pos = writeexp(buf, 1, x, precision, plus, space, hash, expchar, decchar, trimtrailingzeros)
return String(resize!(buf, pos - 1))
end
function Base.show(io::IO, x::T, forceuntyped::Bool=false, fromprint::Bool=false) where {T <: Base.IEEEFloat}
compact = get(io, :compact, false)
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
function Base.string(x::T) where {T <: Base.IEEEFloat}
buf = Base.StringVector(neededdigits(T))
pos = writeshortest(buf, 1, x, false, false, true, -1,
UInt8('e'), false, UInt8('.'), false, false)
return String(resize!(buf, pos - 1))
end
Base.print(io::IO, x::Union{Float16, Float32}) = show(io, x, true, true)
end # module
|