Skip to content
Merged

Grisu #7291

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
f78c9a5
Implement grisu algorithm in native Julia.
quinnj Jun 17, 2014
2b947c3
Merge branch 'master' of https://github.com/JuliaLang/julia into jq/g…
quinnj Jun 17, 2014
8b614c7
Export the grisu method to allow importing by Printf module. Should f…
quinnj Jun 17, 2014
595d019
Merge branch 'master' of https://github.com/JuliaLang/julia into jq/g…
quinnj Jun 17, 2014
29abc80
realmax(Float16) now prints '65500.0' instead of '65504.0' in accorda…
quinnj Jun 18, 2014
858a0e8
1st attempt at removing all double-conversion library traces.
quinnj Jun 18, 2014
30ab714
Add double-conversion LICENSE to grisu folder. Tweak .gitignore
quinnj Jun 23, 2014
84141a6
Merge branch 'master' of https://github.com/JuliaLang/julia into jq/g…
quinnj Jun 24, 2014
bce3e41
Merge branch 'master' of https://github.com/JuliaLang/julia into jq/g…
quinnj Jun 26, 2014
d1b9fb2
Merge branch 'master' of https://github.com/JuliaLang/julia into jq/g…
quinnj Jun 28, 2014
c93cf20
Merge branch 'master' of https://github.com/JuliaLang/julia into jq/g…
quinnj Aug 12, 2014
86b567c
Fix 32-bit overflow in 5^17
quinnj Aug 21, 2014
58fa85c
Ensure correct unsigned arithmetic promotion between 32-bit/64-bit.
quinnj Aug 21, 2014
a6893f8
Merge branch 'master' of https://github.com/JuliaLang/julia into jq/g…
quinnj Aug 21, 2014
7d84a31
Add grisu to the test/Makefile to be able to run make test-grisu
quinnj Aug 21, 2014
4c96830
Merge branch 'master' of https://github.com/JuliaLang/julia into jq/g…
quinnj Aug 27, 2014
4db3b63
Lots of method renaming and split fastdtoa into fastshortest and fast…
quinnj Aug 27, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ notifications:
before_install:
- if [ `uname` = "Linux" ]; then
BUILDOPTS="USEGCC=1 LLVM_CONFIG=llvm-config-3.3 LLVM_LLC=llc-3.3 VERBOSE=1 USE_BLAS64=0";
for lib in LLVM ZLIB SUITESPARSE ARPACK BLAS FFTW LAPACK GMP MPFR PCRE LIBUNWIND GRISU OPENLIBM RMATH; do
for lib in LLVM ZLIB SUITESPARSE ARPACK BLAS FFTW LAPACK GMP MPFR PCRE LIBUNWIND OPENLIBM RMATH; do
export BUILDOPTS="$BUILDOPTS USE_SYSTEM_$lib=1";
done;
sudo apt-get update -qq -y;
sudo apt-get install zlib1g-dev;
sudo add-apt-repository ppa:staticfloat/julia-deps -y;
sudo apt-get update -qq -y;
sudo apt-get install patchelf gfortran llvm-3.3-dev libsuitesparse-dev libopenblas-dev liblapack-dev libarpack2-dev libfftw3-dev libgmp-dev libpcre3-dev libunwind7-dev libdouble-conversion-dev libopenlibm-dev librmath-dev libmpfr-dev -y;
sudo apt-get install patchelf gfortran llvm-3.3-dev libsuitesparse-dev libopenblas-dev liblapack-dev libarpack2-dev libfftw3-dev libgmp-dev libpcre3-dev libunwind7-dev libopenlibm-dev librmath-dev libmpfr-dev -y;
elif [ `uname` = "Darwin" ]; then
brew tap staticfloat/julia;
brew install -v --only-dependencies --HEAD julia;
Expand Down
1 change: 0 additions & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ External libraries, if used, include their own licenses:
- [AMOS](http://www.netlib.org/slatec/guide)
- [ARPACK](http://www.caam.rice.edu/software/ARPACK/RiceBSD.txt#LICENSE)
- [ATLAS](http://math-atlas.sourceforge.net/faq.html#license)
- [DOUBLE-CONVERSION](https://code.google.com/p/double-conversion/)
- [DSFMT](http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/LICENSE.txt)
- [OPENLIBM](https://github.com/JuliaLang/openlibm/blob/master/LICENSE.md)
- [FADDEEVA](http://ab-initio.mit.edu/Faddeeva)
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ $(build_bindir)/stringreplace: $(build_bindir) contrib/stringreplace.c
JL_LIBS = julia julia-debug

# private libraries, that are installed in $(prefix)/lib/julia
JL_PRIVATE_LIBS = suitesparse_wrapper grisu Rmath
JL_PRIVATE_LIBS = suitesparse_wrapper Rmath
ifeq ($(USE_SYSTEM_FFTW),0)
JL_PRIVATE_LIBS += fftw3 fftw3f fftw3_threads fftw3f_threads
endif
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,6 @@ Julia uses the following external libraries, which are automatically downloaded
- **[PCRE]** — Perl-compatible regular expressions library.
- **[GMP]** — the GNU multiple precision arithmetic library, needed for bigint support.
- **[MPFR]** — the GNU multiple precision floating point library, needed for arbitrary precision floating point support.
- **[double-conversion]** — efficient number-to-text conversion.


[GNU make]: http://www.gnu.org/software/make/
Expand Down
139 changes: 63 additions & 76 deletions base/grisu.jl
Original file line number Diff line number Diff line change
@@ -1,77 +1,73 @@
module Grisu

export print_shortest
export @grisu_ccall, NEG, DIGITS, BUFLEN, LEN, POINT
export DIGITS, grisu

import Base.show, Base.print, Base.showcompact
const SHORTEST = 1
const FIXED = 2
const PRECISION = 3

const NEG = Array(Bool)
const DIGITS = Array(Uint8,309+17)
const BUFLEN = int32(length(DIGITS)+1)
const LEN = Array(Int32)
const POINT = Array(Int32)

macro grisu_ccall(value, mode, ndigits)
quote
ccall((:grisu, :libgrisu), Void,
(Float64, Int32, Int32, Ptr{Uint8}, Int32,
Ptr{Bool}, Ptr{Int32}, Ptr{Int32}),
$(esc(value)), $(esc(mode)), $(esc(ndigits)),
DIGITS, BUFLEN, NEG, LEN, POINT)
include("grisu/float.jl")
include("grisu/fastshortest.jl")
include("grisu/fastprecision.jl")
include("grisu/fastfixed.jl")
include("grisu/bignum.jl")

function grisu(v::FloatingPoint,mode,requested_digits,buffer=DIGITS)
if signbit(v)
neg = true
v = -v
else
neg = false
end
if mode == PRECISION && requested_digits == 0
buffer[1] = 0x00
len = 0
return 0, 0, neg, buffer
end
if v == 0.0
buffer[1] = 0x30
buffer[2] = 0x00
len = point = 1
return len, point, neg, buffer
end
if mode == SHORTEST
status,len,point,buf = fastshortest(v,buffer)
elseif mode == FIXED
status,len,point,buf = fastfixedtoa(v,0,requested_digits,buffer)
elseif mode == PRECISION
status,len,point,buf = fastprecision(v,requested_digits,buffer)
end
status && return len-1, point, neg, buf
status, len, point, buf = bignumdtoa(v,mode,requested_digits,buffer)
return len-1, point, neg, buf
end

const SHORTEST = int32(0) # shortest exact representation for doubles
const SHORTEST_SINGLE = int32(1) # shortest exact representation for singles
const FIXED = int32(2) # fixed number of trailing decimal points
const PRECISION = int32(3) # fixed precision regardless of magnitude

# wrapper for the core grisu function, primarily for debugging
function grisu(x::Float64, mode::Integer, ndigits::Integer)
if !isfinite(x); error("non-finite value: $x"); end
if ndigits < 0; error("negative digits requested"); end
@grisu_ccall x mode ndigits
NEG[1], DIGITS[1:LEN[1]], int(POINT[1])
end

grisu(x::Float64) = grisu(x, SHORTEST, int32(0))
grisu(x::Float32) = grisu(float64(x), SHORTEST_SINGLE, int32(0))
grisu(x::Real) = grisu(float(x))

function grisu_fix(x::Real, n::Integer)
if n > 17; n = 17; end
grisu(float64(x), FIXED, int32(n))
end
function grisu_sig(x::Real, n::Integer)
if n > 309; n = 309; end
grisu(float64(x), PRECISION, int32(n))
end

_show(io::IO, x::FloatingPoint, mode::Int32, n::Int, t) =
_show(io::IO, x::FloatingPoint, mode, n::Int, t) =
_show(io, x, mode, n, t, "NaN", "Inf")
_show(io::IO, x::Float32, mode::Int32, n::Int, t) =
_show(io::IO, x::Float32, mode, n::Int, t) =
_show(io, x, mode, n, t, "NaN32", "Inf32")
_show(io::IO, x::Float16, mode::Int32, n::Int, t) =
_show(io::IO, x::Float16, mode, n::Int, t) =
_show(io, x, mode, n, t, "NaN16", "Inf16")

function _show(io::IO, x::FloatingPoint, mode::Int32, n::Int, typed, nanstr, infstr)
if isnan(x) return write(io, typed ? nanstr : "NaN"); end
function _show(io::IO, x::FloatingPoint, mode, n::Int, typed, nanstr, infstr)
isnan(x) && return write(io, typed ? nanstr : "NaN")
if isinf(x)
if x < 0 write(io,'-') end
signbit(x) && write(io,'-')
write(io, typed ? infstr : "Inf")
return
end
if typed && isa(x,Float16) write(io, "float16("); end
@grisu_ccall x mode n
pdigits = pointer(DIGITS)
neg = NEG[1]
len = int(LEN[1])
pt = int(POINT[1])
typed && isa(x,Float16) && write(io, "float16(")
len,pt,neg,buffer = grisu(x,mode,n)
pdigits = pointer(buffer)
if mode == PRECISION
while len > 1 && DIGITS[len] == '0'
while len > 1 && buffer[len] == 0x30
len -= 1
end
end
if neg write(io,'-') end
neg && write(io,'-')
if pt <= -4 || pt > 6 # .00001 to 100000.
# => #.#######e###
write(io, pdigits, 1)
Expand All @@ -83,7 +79,7 @@ function _show(io::IO, x::FloatingPoint, mode::Int32, n::Int, typed, nanstr, inf
end
write(io, typed && isa(x,Float32) ? 'f' : 'e')
write(io, dec(pt-1))
if typed && isa(x,Float16) write(io, ")"); end
typed && isa(x,Float16) && write(io, ")")
return
elseif pt <= 0
# => 0.00########
Expand All @@ -106,21 +102,16 @@ function _show(io::IO, x::FloatingPoint, mode::Int32, n::Int, typed, nanstr, inf
write(io, '.')
write(io, pdigits+pt, len-pt)
end
if typed && isa(x,Float32) write(io, "f0") end
if typed && isa(x,Float16) write(io, ")"); end
typed && isa(x,Float32) && write(io, "f0")
typed && isa(x,Float16) && write(io, ")")
nothing
end

show(io::IO, x::Float64) = _show(io, x, SHORTEST, 0, true)
show(io::IO, x::Float32) = _show(io, x, SHORTEST_SINGLE, 0, true)
show(io::IO, x::Float16) = _show(io, x, PRECISION, 5, true)

print(io::IO, x::Float32) = _show(io, x, SHORTEST_SINGLE, 0, false)
print(io::IO, x::Float16) = _show(io, x, PRECISION, 5, false)
Base.show(io::IO, x::FloatingPoint) = _show(io, x, SHORTEST, 0, true)

showcompact(io::IO, x::Float64) = _show(io, x, PRECISION, 6, false)
showcompact(io::IO, x::Float32) = _show(io, x, PRECISION, 6, false)
showcompact(io::IO, x::Float16) = _show(io, x, PRECISION, 5, false)
Base.showcompact(io::IO, x::Float64) = _show(io, x, PRECISION, 6, false)
Base.showcompact(io::IO, x::Float32) = _show(io, x, PRECISION, 6, false)
Base.showcompact(io::IO, x::Float16) = _show(io, x, PRECISION, 5, false)

# normal:
# 0 < pt < len ####.#### len+1
Expand All @@ -131,14 +122,12 @@ showcompact(io::IO, x::Float16) = _show(io, x, PRECISION, 5, false)
# pt <= 0 ########e-### len+k+2
# 0 < pt ########e### len+k+1

function _print_shortest(io::IO, x::FloatingPoint, dot::Bool, mode::Int32, n::Int)
if isnan(x); return write(io, "NaN"); end
if x < 0 write(io,'-') end
if isinf(x); return write(io, "Inf"); end
@grisu_ccall x mode n
pdigits = pointer(DIGITS)
len = int(LEN[1])
pt = int(POINT[1])
function _print_shortest(io::IO, x::FloatingPoint, 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)
pdigits = pointer(buffer)
e = pt-len
k = -9<=e<=9 ? 1 : 2
if -pt > k+1 || e+dot > k+1
Expand Down Expand Up @@ -173,9 +162,7 @@ function _print_shortest(io::IO, x::FloatingPoint, dot::Bool, mode::Int32, n::In
nothing
end

print_shortest(io::IO, x::Float64, dot::Bool) = _print_shortest(io, x, dot, SHORTEST, 0)
print_shortest(io::IO, x::Float32, dot::Bool) = _print_shortest(io, x, dot, SHORTEST_SINGLE, 0)
print_shortest(io::IO, x::Float16, dot::Bool=false) = _print_shortest(io, x, dot, PRECISION, 5)
print_shortest(io::IO, x::FloatingPoint, dot::Bool) = _print_shortest(io, x, dot, SHORTEST, 0)
print_shortest(io::IO, x::Union(FloatingPoint,Integer)) = print_shortest(io, float(x), false)

end # module
26 changes: 26 additions & 0 deletions base/grisu/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Copyright 2006-2014, the V8 project authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Loading