Skip to content

Commit 869090b

Browse files
committed
Switch float printing from grisu to ryu algorithm
1 parent 6527de0 commit 869090b

26 files changed

+2148
-78
lines changed

LICENSE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ Julia includes code from the following projects, which have their own licenses:
3939

4040
The following components included in Julia `Base` have their own separate licenses:
4141

42+
- base/ryu/* [Boost] (see [ryu](https://github.com/ulfjack/ryu/blob/master/LICENSE-Boost))
4243
- base/grisu/* [BSD-3] (see [double-conversion](https://github.com/google/double-conversion/blob/master/LICENSE))
4344
- base/special/{exp,rem_pio2,hyperbolic}.jl [Freely distributable with preserved copyright notice] (see [FDLIBM](https://www.netlib.org/fdlibm))
4445

base/Base.jl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,10 +303,15 @@ function deepcopy_internal end
303303
include("Enums.jl")
304304
using .Enums
305305

306-
# BigInts and BigFloats
306+
# BigInts
307307
include("gmp.jl")
308308
using .GMP
309309

310+
# float printing: requires BigInt
311+
include("ryu/Ryu.jl")
312+
using .Ryu
313+
314+
# BigFloats
310315
include("mpfr.jl")
311316
using .MPFR
312317

base/docs/basedocs.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,10 +1059,10 @@ Create a `Float32` from `x`. If `x` is not exactly representable then `mode` det
10591059
# Examples
10601060
```jldoctest
10611061
julia> Float32(1/3, RoundDown)
1062-
0.3333333f0
1062+
0.3333333
10631063
10641064
julia> Float32(1/3, RoundUp)
1065-
0.33333334f0
1065+
0.33333334
10661066
```
10671067
10681068
See [`RoundingMode`](@ref) for available rounding modes.

base/essentials.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ julia> x = 1/3
141141
0.3333333333333333
142142
143143
julia> convert(Float32, x)
144-
0.33333334f0
144+
0.33333334
145145
146146
julia> convert(Rational{Int32}, x)
147147
1//3
@@ -402,11 +402,11 @@ For example,
402402
# Examples
403403
```jldoctest
404404
julia> reinterpret(Float32, UInt32(7))
405-
1.0f-44
405+
1.0e-44
406406
407407
julia> reinterpret(Float32, UInt32[1 2 3 4 5])
408408
1×5 reinterpret(Float32, ::Array{UInt32,2}):
409-
1.4013e-45 2.8026e-45 4.2039e-45 5.60519e-45 7.00649e-45
409+
1.0e-45 3.0e-45 4.0e-45 6.0e-45 7.0e-45
410410
```
411411
"""
412412
reinterpret(::Type{T}, x) where {T} = bitcast(T, x)

base/float.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -764,10 +764,10 @@ The highest finite value representable by the given floating-point DataType `T`.
764764
# Examples
765765
```jldoctest
766766
julia> floatmax(Float16)
767-
Float16(6.55e4)
767+
65500.0
768768
769769
julia> floatmax(Float32)
770-
3.4028235f38
770+
3.4028235e38
771771
```
772772
"""
773773
floatmax(x::T) where {T<:AbstractFloat} = floatmax(T)
@@ -790,7 +790,7 @@ julia> eps()
790790
2.220446049250313e-16
791791
792792
julia> eps(Float32)
793-
1.1920929f-7
793+
1.1920929e-7
794794
795795
julia> 1.0 + eps()
796796
1.0000000000000002

base/grisu/grisu.jl

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -154,31 +154,6 @@ function _show(io::IO, x::AbstractFloat, mode, n::Int, typed, compact)
154154
nothing
155155
end
156156

157-
function Base.show(io::IO, x::Union{Float64,Float32})
158-
if get(io, :compact, false)
159-
_show(io, x, PRECISION, 6, x isa Float64, true)
160-
else
161-
_show(io, x, SHORTEST, 0, get(io, :typeinfo, Any) !== typeof(x), false)
162-
end
163-
end
164-
165-
function Base.show(io::IO, x::Float16)
166-
hastypeinfo = Float16 === get(io, :typeinfo, Any)
167-
# if hastypeinfo, the printing would be more compact using `SHORTEST`
168-
# while still retaining all the information
169-
# BUT: we want to print all digits in `show`, not in display, so we rely
170-
# on the :compact property to make the decision
171-
# (cf. https://github.com/JuliaLang/julia/pull/24651#issuecomment-345535687)
172-
if get(io, :compact, false) && !hastypeinfo
173-
_show(io, x, PRECISION, 5, false, true)
174-
else
175-
_show(io, x, SHORTEST, 0, !hastypeinfo, false)
176-
end
177-
end
178-
179-
Base.print(io::IO, x::Float32) = _show(io, x, SHORTEST, 0, false, false)
180-
Base.print(io::IO, x::Float16) = _show(io, x, SHORTEST, 0, false, false)
181-
182157
# normal:
183158
# 0 < pt < len ####.#### len+1
184159
# pt <= 0 0.000######## len-pt+1

base/int.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -638,10 +638,10 @@ The lowest value representable by the given (real) numeric DataType `T`.
638638
# Examples
639639
```jldoctest
640640
julia> typemin(Float16)
641-
-Inf16
641+
-Inf
642642
643643
julia> typemin(Float32)
644-
-Inf32
644+
-Inf
645645
```
646646
"""
647647
function typemin end

base/promotion.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ If no arguments can be converted, an error is raised.
250250
# Examples
251251
```jldoctest
252252
julia> promote(Int8(1), Float16(4.5), Float32(4.1))
253-
(1.0f0, 4.5f0, 4.1f0)
253+
(1.0, 4.5, 4.1)
254254
```
255255
"""
256256
function promote end

base/ryu/LICENSE.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
The code in this directory (base/ryu) is a derivative based on the work in the https://github.com/ulfjack/ryu repository, which allows the use of the Boost software license, included below.
2+
3+
Boost Software License - Version 1.0 - August 17th, 2003
4+
5+
Permission is hereby granted, free of charge, to any person or organization
6+
obtaining a copy of the software and accompanying documentation covered by
7+
this license (the "Software") to use, reproduce, display, distribute,
8+
execute, and transmit the Software, and to prepare derivative works of the
9+
Software, and to permit third-parties to whom the Software is furnished to
10+
do so, all subject to the following:
11+
12+
The copyright notices in the Software and this entire statement, including
13+
the above license grant, this restriction and the following disclaimer,
14+
must be included in all copies of the Software, in whole or in part, and
15+
all derivative works of the Software, unless such copies or derivative
16+
works are solely in the form of machine-executable object code generated by
17+
a source language processor.
18+
19+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
22+
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
23+
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
24+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25+
DEALINGS IN THE SOFTWARE.

base/ryu/Ryu.jl

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
module Ryu
2+
3+
include("utils.jl")
4+
include("shortest.jl")
5+
include("fixed.jl")
6+
include("exp.jl")
7+
8+
neededdigits(::Type{Float64}) = 309 + 17
9+
neededdigits(::Type{Float32}) = 39 + 9
10+
neededdigits(::Type{Float16}) = 9 + 5
11+
12+
"""
13+
Ryu.writeshortest(x, plus=false, space=false, hash=true, precision=-1, expchar=UInt8('e'), padexp=false, decchar=UInt8('.'))
14+
Ryu.writeshortest(buf::Vector{UInt8}, pos::Int, x, args...)
15+
16+
Convert a float value `x` into its "shortest" decimal string, which can be parsed back to the same value.
17+
This function allows achieving the `%g` printf format.
18+
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.
19+
20+
Various options for the output format include:
21+
* `plus`: for positive `x`, prefix decimal string with a `'+'` character
22+
* `space`: for positive `x`, prefix decimal string with a `' '` character; overridden if `plus=true`
23+
* `hash`: whether the decimal point should be written, even if no additional digits are needed for precision
24+
* `precision`: minimum number of significant digits to be included in the decimal string; extra `'0'` characters will be added for padding if necessary
25+
* `expchar`: character to use exponent component in scientific notation
26+
* `padexp`: whether two digits should always be written, even for single-digit exponents (e.g. `e+1` becomes `e+01`)
27+
* `decchar`: decimal point character to be used
28+
"""
29+
function writeshortest(x::T,
30+
plus::Bool=false,
31+
space::Bool=false,
32+
hash::Bool=true,
33+
precision::Integer=-1,
34+
expchar::UInt8=UInt8('e'),
35+
padexp::Bool=false,
36+
decchar::UInt8=UInt8('.')) where {T <: Base.IEEEFloat}
37+
buf = Base.StringVector(neededdigits(T))
38+
pos = writeshortest(buf, 1, x)
39+
@assert pos - 1 <= length(buf)
40+
return String(resize!(buf, pos - 1))
41+
end
42+
43+
"""
44+
Ryu.writefixed(x, plus=false, space=false, hash=true, precision=-1, decchar=UInt8('.'))
45+
Ryu.writefixed(buf::Vector{UInt8}, pos::Int, x, args...)
46+
47+
Convert a float value `x` into a "fixed" size decimal string.
48+
This function allows achieving the `%f` printf format.
49+
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.
50+
51+
Various options for the output format include:
52+
* `plus`: for positive `x`, prefix decimal string with a `'+'` character
53+
* `space`: for positive `x`, prefix decimal string with a `' '` character; overridden if `plus=true`
54+
* `hash`: whether the decimal point should be written, even if no additional digits are needed for precision
55+
* `precision`: minimum number of significant digits to be included in the decimal string; extra `'0'` characters will be added for padding if necessary
56+
* `decchar`: decimal point character to be used
57+
"""
58+
function writefixed(x::T, precision) where {T <: Base.IEEEFloat}
59+
buf = Base.StringVector(precision + neededdigits(T))
60+
pos = writefixed(buf, 1, x, false, false, false, precision)
61+
@assert pos - 1 <= length(buf)
62+
return String(resize!(buf, pos - 1))
63+
end
64+
65+
"""
66+
Ryu.writeexp(x, plus=false, space=false, hash=true, precision=-1, expchar=UInt8('e'), decchar=UInt8('.'))
67+
Ryu.writeexp(buf::Vector{UInt8}, pos::Int, x, args...)
68+
69+
Convert a float value `x` into a scientific notation decimal string.
70+
This function allows achieving the `%e` printf format.
71+
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.
72+
73+
Various options for the output format include:
74+
* `plus`: for positive `x`, prefix decimal string with a `'+'` character
75+
* `space`: for positive `x`, prefix decimal string with a `' '` character; overridden if `plus=true`
76+
* `hash`: whether the decimal point should be written, even if no additional digits are needed for precision
77+
* `precision`: minimum number of significant digits to be included in the decimal string; extra `'0'` characters will be added for padding if necessary
78+
* `expchar`: character to use exponent component in scientific notation
79+
* `decchar`: decimal point character to be used
80+
"""
81+
function writeexp(x::T, precision) where {T <: Base.IEEEFloat}
82+
buf = Base.StringVector(precision + neededdigits(T))
83+
pos = writeexp(buf, 1, x, false, false, false, precision)
84+
@assert pos - 1 <= length(buf)
85+
return String(resize!(buf, pos - 1))
86+
end
87+
88+
function Base.show(io::IO, x::T) where {T <: Base.IEEEFloat}
89+
if get(io, :compact, false)
90+
x = round(x, sigdigits=6)
91+
end
92+
buf = Base.StringVector(neededdigits(T))
93+
pos = writeshortest(buf, 1, x)
94+
@assert pos - 1 <= length(buf)
95+
write(io, resize!(buf, pos - 1))
96+
return
97+
end
98+
99+
end # module

0 commit comments

Comments
 (0)