/base/grisu.jl

https://github.com/biegelk/julia · Lisp · 164 lines · 151 code · 13 blank · 0 comment · 31 complexity · e340aaab58704dc01bccc49784cc4f92 MD5 · raw file

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