Skip to content

Commit

Permalink
more float to string performance improvements
Browse files Browse the repository at this point in the history
- some tuples used in grisu were heap allocated. the `buffer`
  element was not really needed.
- fixed a type instability in Grisu.normalize
- provide a good size hint for floats in print_to_string to
  avoid excess reallocation.

before:

```
julia> @time for i=1:10^7;string(3.141592653);end
  6.402762 seconds (80.00 M allocations: 2.831 GB, 3.91% gc time)
```

after:

```
julia> @time for i=1:10^7;string(3.141592653);end
  4.038174 seconds (30.00 M allocations: 1.639 GB, 2.29% gc time)
```
  • Loading branch information
JeffBezanson committed Jan 12, 2016
1 parent 2b12e96 commit 53ecbaa
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 75 deletions.
12 changes: 6 additions & 6 deletions base/grisu.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ function grisu(v::AbstractFloat,mode,requested_digits,buffer=DIGITS,bignums=BIGN
if mode == PRECISION && requested_digits == 0
buffer[1] = 0x00
len = 0
return 0, 0, neg, buffer
return 0, 0, neg
end
if v == 0.0
buffer[1] = 0x30
buffer[2] = 0x00
len = point = 1
return len, point, neg, buffer
return len, point, neg
end
if mode == SHORTEST
status,len,point = fastshortest(v,buffer)
Expand All @@ -47,9 +47,9 @@ function grisu(v::AbstractFloat,mode,requested_digits,buffer=DIGITS,bignums=BIGN
elseif mode == PRECISION
status,len,point = fastprecision(v,requested_digits,buffer)
end
status && return len-1, point, neg, buffer
status && return len-1, point, neg
status, len, point = bignumdtoa(v,mode,requested_digits,buffer,bignums)
return len-1, point, neg, buffer
return len-1, point, neg
end

_show(io::IO, x::AbstractFloat, mode, n::Int, t) =
Expand All @@ -67,7 +67,7 @@ function _show(io::IO, x::AbstractFloat, mode, n::Int, typed, nanstr, infstr)
return
end
typed && isa(x,Float16) && write(io, "Float16(")
len,pt,neg,buffer = grisu(x,mode,n)
(len,pt,neg),buffer = grisu(x,mode,n),DIGITS
pdigits = pointer(buffer)
if mode == PRECISION
while len > 1 && buffer[len] == 0x30
Expand Down Expand Up @@ -138,7 +138,7 @@ function _print_shortest(io::IO, x::AbstractFloat, dot::Bool, mode, n::Int)
isnan(x) && return write(io, "NaN")
x < 0 && write(io,'-')
isinf(x) && return write(io, "Inf")
len,pt,neg,buffer = grisu(x,mode,n)
(len,pt,neg),buffer = grisu(x,mode,n),DIGITS
pdigits = pointer(buffer)
e = pt-len
k = -9<=e<=9 ? 1 : 2
Expand Down
2 changes: 1 addition & 1 deletion base/grisu/float.jl
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const FloatSignificandSize = Int32(64)

function normalize(v::Float)
f = v.s
e = v.e
e::Int32 = v.e
while (f & Float10MSBits) == 0
f <<= 10
e -= 10
Expand Down
6 changes: 3 additions & 3 deletions base/printf.jl
Original file line number Diff line number Diff line change
Expand Up @@ -909,7 +909,7 @@ function decode_dec(x::SmallFloatingPoint)
DIGITS[1] = '0'
return (Int32(1), Int32(1), false)
end
len,pt,neg,buffer = grisu(x,Grisu.FIXED,0)
len,pt,neg = grisu(x,Grisu.FIXED,0)
if len == 0
DIGITS[1] = '0'
return (Int32(1), Int32(1), false)
Expand All @@ -935,7 +935,7 @@ fix_dec(x::Integer, n::Int) = decode_dec(x)

function fix_dec(x::SmallFloatingPoint, n::Int)
if n > length(DIGITS)-1; n = length(DIGITS)-1; end
len,pt,neg,buffer = grisu(x,Grisu.FIXED,n)
len,pt,neg = grisu(x,Grisu.FIXED,n)
if len == 0
DIGITS[1] = '0'
return (Int32(1), Int32(1), neg)
Expand Down Expand Up @@ -989,7 +989,7 @@ function ini_dec(x::SmallFloatingPoint, n::Int)
ccall(:memset, Ptr{Void}, (Ptr{Void}, Cint, Csize_t), DIGITS, '0', n)
return Int32(1), Int32(1), signbit(x)
else
len,pt,neg,buffer = grisu(x,Grisu.PRECISION,n)
len,pt,neg = grisu(x,Grisu.PRECISION,n)
end
return Int32(len), Int32(pt), neg
end
Expand Down
7 changes: 6 additions & 1 deletion base/strings/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,14 @@ function sprint(size::Integer, f::Function, args...; env=nothing)
end
sprint(f::Function, args...) = sprint(0, f, args...)

tostr_sizehint(x) = 0
tostr_sizehint(x::AbstractString) = endof(x)
tostr_sizehint(x::Float64) = 20
tostr_sizehint(x::Float32) = 12

function print_to_string(xs...; env=nothing)
# specialized for performance reasons
s = IOBuffer(Array(UInt8,isa(xs[1],AbstractString) ? endof(xs[1]) : 0), true, true)
s = IOBuffer(Array(UInt8,tostr_sizehint(xs[1])), true, true)
# specialized version of truncate(s,0)
s.size = 0
s.ptr = 1
Expand Down
Loading

1 comment on commit 53ecbaa

@quinnj
Copy link
Member

@quinnj quinnj commented on 53ecbaa Jan 16, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool!

Please sign in to comment.