/base/grisu.jl

https://github.com/SinSiXX/julia · Lisp · 181 lines · 165 code · 16 blank · 0 comment · 41 complexity · 6f3e0703124446ad07578a479df5aa6f MD5 · raw file

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