Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Grisu #7291

Merged
merged 17 commits into from
Aug 27, 2014
Merged

Grisu #7291

Show file tree
Hide file tree
Changes from 6 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
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ before_install:
- 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
script:
- make $BUILDOPTS prefix=/tmp/julia install
- cd .. && mv julia julia2
Expand Down
1 change: 0 additions & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ External libraries, if used, include their own licenses:
- [ARPACK](http://www.caam.rice.edu/software/ARPACK/RiceBSD.txt#LICENSE)
- [ATLAS](http://math-atlas.sourceforge.net/faq.html#license)
- [D3](https://github.com/mbostock/d3/raw/master/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 @@ -104,7 +104,7 @@ $(build_bindir)/stringpatch: $(build_bindir) contrib/stringpatch.c
JL_LIBS = julia julia-debug

# private libraries, that are installed in $(prefix)/lib/julia
JL_PRIVATE_LIBS = random suitesparse_wrapper grisu Rmath
JL_PRIVATE_LIBS = random 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 @@ -214,7 +214,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
142 changes: 66 additions & 76 deletions base/grisu.jl
Original file line number Diff line number Diff line change
@@ -1,77 +1,76 @@
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/fastdtoa.jl")
include("grisu/fastfixedtoa.jl")
include("grisu/bignum-dtoa.jl")

#TODO
#remove double-conversion from makefiles
#what to do with tests? everything but mega files?

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 = fastdtoa(v,SHORTEST,0,buffer)
elseif mode == FIXED
status,len,point,buf = fastfixedtoa(v,0,requested_digits,buffer)
elseif mode == PRECISION
status,len,point,buf = fastdtoa(v,PRECISION,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 +82,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 +105,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 +125,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 +165,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
Loading