/base/grisu.jl

https://github.com/mattsommer/julia · Julia · 162 lines · 133 code · 14 blank · 15 comment · 31 complexity · 6eed4b397b4a8f1ec0ff5a6e9e1717ec MD5 · raw file

  1. libgrisu = dlopen("libgrisu")
  2. module Grisu
  3. using Base
  4. export print_shortest
  5. export @grisu_ccall, NEG, DIGITS, BUFLEN, LEN, POINT
  6. import Base.show, Base.showcompact
  7. const NEG = Array(Bool,1)
  8. const DIGITS = Array(Uint8,309+17)
  9. const BUFLEN = int32(length(DIGITS)+1)
  10. const LEN = Array(Int32,1)
  11. const POINT = Array(Int32,1)
  12. macro grisu_ccall(value, mode, ndigits)
  13. quote
  14. ccall(dlsym(Base.libgrisu, :grisu), Void,
  15. (Float64, Int32, Int32, Ptr{Uint8}, Int32,
  16. Ptr{Bool}, Ptr{Int32}, Ptr{Int32}),
  17. $(esc(value)), $(esc(mode)), $(esc(ndigits)),
  18. DIGITS, BUFLEN, NEG, LEN, POINT)
  19. end
  20. end
  21. const SHORTEST = int32(0) # shortest exact representation for doubles
  22. const SHORTEST_SINGLE = int32(1) # shortest exact representation for singles
  23. const FIXED = int32(2) # fixed number of trailing decimal points
  24. const PRECISION = int32(3) # fixed precision regardless of magnitude
  25. # wrapper for the core grisu function, primarily for debugging
  26. function grisu(x::Float64, mode::Integer, ndigits::Integer)
  27. if !isfinite(x); error("non-finite value: $x"); end
  28. if ndigits < 0; error("negative digits requested"); end
  29. @grisu_ccall x mode ndigits
  30. NEG[1], DIGITS[1:LEN[1]], POINT[1]
  31. end
  32. grisu(x::Float64) = grisu(x, SHORTEST, int32(0))
  33. grisu(x::Float32) = grisu(float64(x), SHORTEST_SINGLE, int32(0))
  34. grisu(x::Real) = grisu(float(x))
  35. function grisu_fix(x::Real, n::Integer)
  36. if n > 17; n = 17; end
  37. grisu(float64(x), FIXED, int32(n))
  38. end
  39. function grisu_sig(x::Real, n::Integer)
  40. if n > 309; n = 309; end
  41. grisu(float64(x), PRECISION, int32(n))
  42. end
  43. function _show(io, x::FloatingPoint, mode::Int32, n::Int)
  44. if isnan(x); return write(io, isa(x,Float32) ? "NaN32" : "NaN"); end
  45. if x < 0 write(io,'-') end
  46. if isinf(x); return write(io, isa(x,Float32) ? "Inf32" : "Inf"); end
  47. @grisu_ccall x mode n
  48. pdigits = pointer(DIGITS)
  49. len = LEN[1]
  50. pt = POINT[1]
  51. if mode == PRECISION
  52. while len > 1 && DIGITS[len] == '0'
  53. len -= 1
  54. end
  55. end
  56. if pt <= -4 || pt > 6 # .00001 to 100000.
  57. # => #.#######e###
  58. write(io, pdigits, 1)
  59. write(io, '.')
  60. if len > 1
  61. write(io, pdigits+1, len-1)
  62. else
  63. write(io, '0')
  64. end
  65. write(io, isa(x,Float32) ? 'f' : 'e')
  66. write(io, dec(pt-1))
  67. return
  68. elseif pt <= 0
  69. # => 0.00########
  70. write(io, "0.")
  71. while pt < 0
  72. write(io, '0')
  73. pt += 1
  74. end
  75. write(io, pdigits, len)
  76. elseif pt >= len
  77. # => ########00.0
  78. write(io, pdigits, len)
  79. while pt > len
  80. write(io, '0')
  81. len += 1
  82. end
  83. write(io, ".0")
  84. else # => ####.####
  85. write(io, pdigits, pt)
  86. write(io, '.')
  87. write(io, pdigits+pt, len-pt)
  88. end
  89. if isa(x,Float32) write(io, "f0") end
  90. nothing
  91. end
  92. show(io, x::Float64) = _show(io, x, SHORTEST, 0)
  93. show(io, x::Float32) = _show(io, x, SHORTEST_SINGLE, 0)
  94. showcompact(io, x::FloatingPoint) = _show(io, x, PRECISION, 6)
  95. # normal:
  96. # 0 < pt < len ####.#### len+1
  97. # pt <= 0 .000######## len-pt+1
  98. # len <= pt (dot) ########000. pt+1
  99. # len <= pt (no dot) ########000 pt
  100. # exponential:
  101. # pt <= 0 ########e-### len+k+2
  102. # 0 < pt ########e### len+k+1
  103. function _print_shortest(io, x::FloatingPoint, dot::Bool, mode::Int32)
  104. if isnan(x); return write(io, isa(x,Float32) ? "NaN32" : "NaN"); end
  105. if x < 0 write(io,'-') end
  106. if isinf(x); return write(io, isa(x,Float32) ? "Inf32" : "Inf"); end
  107. @grisu_ccall x mode 0
  108. pdigits = pointer(DIGITS)
  109. len = LEN[1]
  110. pt = POINT[1]
  111. e = pt-len
  112. k = -9<=e<=9 ? 1 : 2
  113. if -pt > k+1 || e+dot > k+1
  114. # => ########e###
  115. write(io, pdigits+0, len)
  116. write(io, isa(x,Float32) ? 'f' : 'e')
  117. write(io, dec(e))
  118. return
  119. elseif pt <= 0
  120. # => .000########
  121. write(io, '.')
  122. while pt < 0
  123. write(io, '0')
  124. pt += 1
  125. end
  126. write(io, pdigits+0, len)
  127. elseif e >= dot
  128. # => ########000.
  129. write(io, pdigits+0, len)
  130. while e > 0
  131. write(io, '0')
  132. e -= 1
  133. end
  134. if dot
  135. write(io, '.')
  136. end
  137. else # => ####.####
  138. write(io, pdigits+0, pt)
  139. write(io, '.')
  140. write(io, pdigits+pt, len-pt)
  141. end
  142. if isa(x,Float32) write(io, "f0") end
  143. nothing
  144. end
  145. print_shortest(io, x::Float64, dot::Bool) = _print_shortest(io, x, dot, SHORTEST)
  146. print_shortest(io, x::Float32, dot::Bool) = _print_shortest(io, x, dot, SHORTEST_SINGLE)
  147. print_shortest(io, x::Union(FloatingPoint,Integer)) = print_shortest(io, float(x), false)
  148. end # module