StatProfilerHTML.jl report
Generated on tor 10 okt 2019 11:38:33
File source code
Line Exclusive Inclusive Code
1 # This file is a part of Julia. License is MIT: https://julialang.org/license
2
3 module Grisu
4
5 export print_shortest
6 export DIGITS, DIGITSs, grisu
7
8 const SHORTEST = 1
9 const FIXED = 2
10 const PRECISION = 3
11
12 include("grisu/float.jl")
13 include("grisu/fastshortest.jl")
14 include("grisu/fastprecision.jl")
15 include("grisu/fastfixed.jl")
16 include("grisu/bignums.jl")
17 include("grisu/bignum.jl")
18
19 const DIGITS = Vector{UInt8}(undef, 309+17)
20 const BIGNUMS = [Bignums.Bignum(),Bignums.Bignum(),Bignums.Bignum(),Bignums.Bignum()]
21
22 # thread-safe code should use a per-thread DIGITS buffer DIGITSs[Threads.threadid()]
23 const DIGITSs = [DIGITS]
24 const BIGNUMSs = [BIGNUMS]
25 function __init__()
26 Threads.resize_nthreads!(DIGITSs)
27 Threads.resize_nthreads!(BIGNUMSs)
28 end
29
30 """
31 (len, point, neg) = Grisu.grisu(v::AbstractFloat, mode, requested_digits,
32 buffer=DIGITSs[Threads.threadid()], bignums=BIGNUMSs[Threads.threadid()])
33
34 Convert the number `v` to decimal using the Grisu algorithm.
35
36 `mode` can be one of:
37 - `Grisu.SHORTEST`: convert to the shortest decimal representation which can be "round-tripped" back to `v`.
38 - `Grisu.FIXED`: round to `requested_digits` digits.
39 - `Grisu.PRECISION`: round to `requested_digits` significant digits.
40
41 The characters are written as bytes to `buffer`, with a terminating NUL byte, and `bignums` are used internally as part of the correction step.
42
43 The returned tuple contains:
44
45 - `len`: the number of digits written to `buffer` (excluding NUL)
46 - `point`: the location of the radix point relative to the start of the array (e.g. if
47 `point == 3`, then the radix point should be inserted between the 3rd and 4th
48 digit). Note that this can be negative (for very small values), or greater than `len`
49 (for very large values).
50 - `neg`: the signbit of `v` (see [`signbit`](@ref)).
51 """
52
12 (28.57%) samples spent in grisu
0 (ex.), 12 (100.00%) (incl.) when called from _show line 97
1 (100.00%) (ex.), 12 (100.00%) (incl.) when called from grisu line 53
function grisu(v::AbstractFloat,mode,requested_digits,buffer=DIGITSs[Threads.threadid()],bignums=BIGNUMSs[Threads.threadid()])
53 12 (28.57%)
12 (100.00%) samples spent calling grisu
if signbit(v)
54 neg = true
55 v = -v
56 else
57 neg = false
58 end
59 if mode == PRECISION && requested_digits == 0
60 buffer[1] = 0x00
61 len = 0
62 return 0, 0, neg
63 end
64 if v == 0.0
65 buffer[1] = 0x30
66 buffer[2] = 0x00
67 len = point = 1
68 return len, point, neg
69 end
70 if mode == SHORTEST
71 11 (26.19%)
11 (100.00%) samples spent calling fastshortest
status,len,point = fastshortest(v,buffer)
72 elseif mode == FIXED
73 status,len,point = fastfixedtoa(v,0,requested_digits,buffer)
74 elseif mode == PRECISION
75 status,len,point = fastprecision(v,requested_digits,buffer)
76 end
77 status && return len-1, point, neg
78 status, len, point = bignumdtoa(v,mode,requested_digits,buffer,bignums)
79 return len-1, point, neg
80 end
81
82 nanstr(x::AbstractFloat) = "NaN"
83 nanstr(x::Float32) = "NaN32"
84 nanstr(x::Float16) = "NaN16"
85 infstr(x::AbstractFloat) = "Inf"
86 infstr(x::Float32) = "Inf32"
87 infstr(x::Float16) = "Inf16"
88
89
14 (33.33%) samples spent in _show
0 (ex.), 14 (100.00%) (incl.) when called from show line 151
function _show(io::IO, x::AbstractFloat, mode, n::Int, typed, compact)
90 isnan(x) && return print(io, typed ? nanstr(x) : "NaN")
91 if isinf(x)
92 signbit(x) && print(io,'-')
93 print(io, typed ? infstr(x) : "Inf")
94 return
95 end
96 typed && isa(x,Float16) && print(io, "Float16(")
97 12 (28.57%)
12 (100.00%) samples spent calling grisu
(len,pt,neg),buffer = grisu(x,mode,n),DIGITSs[Threads.threadid()]
98 pdigits = pointer(buffer)
99 if mode == PRECISION
100 while len > 1 && buffer[len] == 0x30
101 len -= 1
102 end
103 end
104 neg && print(io,'-')
105 exp_form = pt <= -4 || pt > 6
106 exp_form = exp_form || (pt >= len && abs(mod(x + 0.05, 10^(pt - len)) - 0.05) > 0.05) # see issue #6608
107 if exp_form # .00001 to 100000.
108 # => #.#######e###
109 # assumes ASCII/UTF8 encoding of digits is okay for out:
110 unsafe_write(io, pdigits, 1)
111 print(io, '.')
112 if len > 1
113 unsafe_write(io, pdigits+1, len-1)
114 else
115 print(io, '0')
116 end
117 print(io, (typed && isa(x,Float32)) ? 'f' : 'e')
118 print(io, string(pt - 1))
119 typed && isa(x,Float16) && print(io, ")")
120 return
121 elseif pt <= 0
122 # => 0.00########
123 1 (2.38%)
1 (100.00%) samples spent calling print
print(io, "0.")
124 while pt < 0
125 print(io, '0')
126 pt += 1
127 end
128 1 (2.38%)
1 (100.00%) samples spent calling unsafe_write
unsafe_write(io, pdigits, len)
129 elseif pt >= len
130 # => ########00.0
131 unsafe_write(io, pdigits, len)
132 while pt > len
133 print(io, '0')
134 len += 1
135 end
136 print(io, ".0")
137 else # => ####.####
138 unsafe_write(io, pdigits, pt)
139 print(io, '.')
140 unsafe_write(io, pdigits+pt, len-pt)
141 end
142 typed && !compact && isa(x,Float32) && print(io, "f0")
143 typed && isa(x,Float16) && print(io, ")")
144 nothing
145 end
146
147 function Base.show(io::IO, x::Union{Float64,Float32})
148 if get(io, :compact, false)
149 _show(io, x, PRECISION, 6, x isa Float64, true)
150 else
151 14 (33.33%)
14 (33.33%) samples spent in show
0 (ex.), 14 (100.00%) (incl.) when called from print line 31
14 (100.00%) samples spent calling _show
_show(io, x, SHORTEST, 0, get(io, :typeinfo, Any) !== typeof(x), false)
152 end
153 end
154
155 function Base.show(io::IO, x::Float16)
156 hastypeinfo = Float16 === get(io, :typeinfo, Any)
157 # if hastypeinfo, the printing would be more compact using `SHORTEST`
158 # while still retaining all the information
159 # BUT: we want to print all digits in `show`, not in display, so we rely
160 # on the :compact property to make the decision
161 # (cf. https://github.com/JuliaLang/julia/pull/24651#issuecomment-345535687)
162 if get(io, :compact, false) && !hastypeinfo
163 _show(io, x, PRECISION, 5, false, true)
164 else
165 _show(io, x, SHORTEST, 0, !hastypeinfo, false)
166 end
167 end
168
169 Base.print(io::IO, x::Float32) = _show(io, x, SHORTEST, 0, false, false)
170 Base.print(io::IO, x::Float16) = _show(io, x, SHORTEST, 0, false, false)
171
172 # normal:
173 # 0 < pt < len ####.#### len+1
174 # pt <= 0 0.000######## len-pt+1
175 # len <= pt (dot) ########000. pt+1
176 # len <= pt (no dot) ########000 pt
177 # exponential:
178 # pt <= 0 ########e-### len+k+2
179 # 0 < pt ########e### len+k+1
180
181 function _print_shortest(io::IO, x::AbstractFloat, dot::Bool, mode, n::Int)
182 isnan(x) && return print(io, "NaN")
183 x < 0 && print(io,'-')
184 isinf(x) && return print(io, "Inf")
185 (len,pt,neg),buffer = grisu(x,mode,n),DIGITSs[Threads.threadid()]
186 pdigits = pointer(buffer)
187 e = pt-len
188 k = -9<=e<=9 ? 1 : 2
189 if -pt > k+1 || e+dot > k+1
190 # => ########e###
191 unsafe_write(io, pdigits+0, len)
192 print(io, 'e')
193 print(io, string(e))
194 return
195 elseif pt <= 0
196 # => 0.000########
197 print(io, "0.")
198 while pt < 0
199 print(io, '0')
200 pt += 1
201 end
202 unsafe_write(io, pdigits+0, len)
203 elseif e >= dot
204 # => ########000.
205 unsafe_write(io, pdigits+0, len)
206 while e > 0
207 print(io, '0')
208 e -= 1
209 end
210 if dot
211 print(io, '.')
212 end
213 else # => ####.####
214 unsafe_write(io, pdigits+0, pt)
215 print(io, '.')
216 unsafe_write(io, pdigits+pt, len-pt)
217 end
218 nothing
219 end
220
221 """
222 print_shortest(io::IO, x)
223
224 Print the shortest possible representation, with the minimum number of consecutive non-zero
225 digits, of number `x`, ensuring that it would parse to the exact same number.
226 """
227 print_shortest(io::IO, x::AbstractFloat, dot::Bool) = _print_shortest(io, x, dot, SHORTEST, 0)
228 print_shortest(io::IO, x::Union{AbstractFloat,Integer}) = print_shortest(io, float(x), false)
229
230 end # module