/base/grisu.jl

https://github.com/chaoqing/julia · Lisp · 159 lines · 146 code · 13 blank · 0 comment · 33 complexity · 5cdfa0e5dbf9a2489039b65d73812d81 MD5 · raw file

  1. module Grisu
  2. export print_shortest
  3. export @grisu_ccall, NEG, DIGITS, BUFLEN, LEN, POINT
  4. import Base.show, Base.showcompact
  5. const NEG = Array(Bool,1)
  6. const DIGITS = Array(Uint8,309+17)
  7. const BUFLEN = int32(length(DIGITS)+1)
  8. const LEN = Array(Int32,1)
  9. const POINT = Array(Int32,1)
  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]], 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. function _show(io, x::FloatingPoint, mode::Int32, n::Int)
  42. if isnan(x); return write(io, isa(x,Float32) ? "NaN32" : "NaN"); end
  43. if x < 0 write(io,'-') end
  44. if isinf(x); return write(io, isa(x,Float32) ? "Inf32" : "Inf"); end
  45. @grisu_ccall x mode n
  46. pdigits = pointer(DIGITS)
  47. len = LEN[1]
  48. pt = POINT[1]
  49. if mode == PRECISION
  50. while len > 1 && DIGITS[len] == '0'
  51. len -= 1
  52. end
  53. end
  54. if pt <= -4 || pt > 6 # .00001 to 100000.
  55. # => #.#######e###
  56. write(io, pdigits, 1)
  57. write(io, '.')
  58. if len > 1
  59. write(io, pdigits+1, len-1)
  60. else
  61. write(io, '0')
  62. end
  63. write(io, isa(x,Float32) ? 'f' : 'e')
  64. write(io, dec(pt-1))
  65. return
  66. elseif pt <= 0
  67. # => 0.00########
  68. write(io, "0.")
  69. while pt < 0
  70. write(io, '0')
  71. pt += 1
  72. end
  73. write(io, pdigits, len)
  74. elseif pt >= len
  75. # => ########00.0
  76. write(io, pdigits, len)
  77. while pt > len
  78. write(io, '0')
  79. len += 1
  80. end
  81. write(io, ".0")
  82. else # => ####.####
  83. write(io, pdigits, pt)
  84. write(io, '.')
  85. write(io, pdigits+pt, len-pt)
  86. end
  87. if isa(x,Float32) write(io, "f0") end
  88. nothing
  89. end
  90. show(io, x::Float64) = _show(io, x, SHORTEST, 0)
  91. show(io, x::Float32) = _show(io, x, SHORTEST_SINGLE, 0)
  92. showcompact(io, x::FloatingPoint) = _show(io, x, PRECISION, 6)
  93. # normal:
  94. # 0 < pt < len ####.#### len+1
  95. # pt <= 0 .000######## len-pt+1
  96. # len <= pt (dot) ########000. pt+1
  97. # len <= pt (no dot) ########000 pt
  98. # exponential:
  99. # pt <= 0 ########e-### len+k+2
  100. # 0 < pt ########e### len+k+1
  101. function _print_shortest(io, x::FloatingPoint, dot::Bool, mode::Int32)
  102. if isnan(x); return write(io, isa(x,Float32) ? "NaN32" : "NaN"); end
  103. if x < 0 write(io,'-') end
  104. if isinf(x); return write(io, isa(x,Float32) ? "Inf32" : "Inf"); end
  105. @grisu_ccall x mode 0
  106. pdigits = pointer(DIGITS)
  107. len = LEN[1]
  108. pt = POINT[1]
  109. e = pt-len
  110. k = -9<=e<=9 ? 1 : 2
  111. if -pt > k+1 || e+dot > k+1
  112. # => ########e###
  113. write(io, pdigits+0, len)
  114. write(io, isa(x,Float32) ? 'f' : 'e')
  115. write(io, dec(e))
  116. return
  117. elseif pt <= 0
  118. # => .000########
  119. write(io, '.')
  120. while pt < 0
  121. write(io, '0')
  122. pt += 1
  123. end
  124. write(io, pdigits+0, len)
  125. elseif e >= dot
  126. # => ########000.
  127. write(io, pdigits+0, len)
  128. while e > 0
  129. write(io, '0')
  130. e -= 1
  131. end
  132. if dot
  133. write(io, '.')
  134. end
  135. else # => ####.####
  136. write(io, pdigits+0, pt)
  137. write(io, '.')
  138. write(io, pdigits+pt, len-pt)
  139. end
  140. if isa(x,Float32) write(io, "f0") end
  141. nothing
  142. end
  143. print_shortest(io, x::Float64, dot::Bool) = _print_shortest(io, x, dot, SHORTEST)
  144. print_shortest(io, x::Float32, dot::Bool) = _print_shortest(io, x, dot, SHORTEST_SINGLE)
  145. print_shortest(io, x::Union(FloatingPoint,Integer)) = print_shortest(io, float(x), false)
  146. end # module