/base/grisu.jl

https://github.com/lcw/julia · Lisp · 162 lines · 149 code · 13 blank · 0 comment · 31 complexity · 0a3e446638aa36cb7ecfc8c304a20a99 MD5 · raw file

  1. libgrisu = dlopen("libgrisu")
  2. module Grisu
  3. import Base.*
  4. export @grisu_ccall, NEG, DIGITS, BUFLEN, LEN, POINT
  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(dlsym(Base.libgrisu, :grisu), 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. global grisu, grisu_fix, grisu_sig
  25. function grisu(x::Float64, mode::Integer, ndigits::Integer)
  26. if !isfinite(x); error("non-finite value: $x"); end
  27. if ndigits < 0; error("negative digits requested"); end
  28. @grisu_ccall x mode ndigits
  29. NEG[1], DIGITS[1:LEN[1]], POINT[1]
  30. end
  31. grisu(x::Float64) = grisu(x, SHORTEST, int32(0))
  32. grisu(x::Float32) = grisu(float64(x), SHORTEST_SINGLE, int32(0))
  33. grisu(x::Real) = grisu(float(x))
  34. function grisu_fix(x::Real, n::Integer)
  35. if n > 17; n = 17; end
  36. grisu(float64(x), FIXED, int32(n))
  37. end
  38. function grisu_sig(x::Real, n::Integer)
  39. if n > 309; n = 309; end
  40. grisu(float64(x), PRECISION, int32(n))
  41. end
  42. function _show(io, x::Float, mode::Int32, n::Int)
  43. if isnan(x); return write(io, "NaN"); end
  44. if isinf(x); return write(io, x < 0 ? "-Inf" : "Inf"); end
  45. @grisu_ccall x mode n
  46. pdigits = pointer(DIGITS)
  47. neg = NEG[1]
  48. len = LEN[1]
  49. pt = POINT[1]
  50. if mode == PRECISION
  51. while len > 1 && DIGITS[len] == '0'
  52. len -= 1
  53. end
  54. end
  55. if neg
  56. write(io, '-')
  57. end
  58. if pt <= -4 || pt > 6 # .00001 to 100000.
  59. # => #.#######e###
  60. write(io, pdigits, 1)
  61. write(io, '.')
  62. if len > 1
  63. write(io, pdigits+1, len-1)
  64. else
  65. write(io, '0')
  66. end
  67. write(io, 'e')
  68. write(io, dec(pt-1))
  69. elseif pt <= 0
  70. # => 0.00########
  71. write(io, "0.")
  72. while pt < 0
  73. write(io, '0')
  74. pt += 1
  75. end
  76. write(io, pdigits, len)
  77. elseif pt >= len
  78. # => ########00.0
  79. write(io, pdigits, len)
  80. while pt > len
  81. write(io, '0')
  82. len += 1
  83. end
  84. write(io, ".0")
  85. else # => ####.####
  86. write(io, pdigits, pt)
  87. write(io, '.')
  88. write(io, pdigits+pt, len-pt)
  89. 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::Float) = _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::Float, dot::Bool, mode::Int32)
  104. if isnan(x); return write(io, "NaN"); end
  105. if isinf(x); return write(io, x < 0 ? "-Inf" : "Inf"); end
  106. @grisu_ccall x mode 0
  107. pdigits = pointer(DIGITS)
  108. neg = NEG[1]
  109. len = LEN[1]
  110. pt = POINT[1]
  111. if neg
  112. write(io, '-')
  113. end
  114. e = pt-len
  115. k = -9<=e<=9 ? 1 : 2
  116. if -pt > k+1 || e+dot > k+1
  117. # => ########e###
  118. write(io, pdigits+0, len)
  119. write(io, 'e')
  120. write(io, dec(e))
  121. elseif pt <= 0
  122. # => .000########
  123. write(io, '.')
  124. while pt < 0
  125. write(io, '0')
  126. pt += 1
  127. end
  128. write(io, pdigits+0, len)
  129. elseif e >= dot
  130. # => ########000.
  131. write(io, pdigits+0, len)
  132. while e > 0
  133. write(io, '0')
  134. e -= 1
  135. end
  136. if dot
  137. write(io, '.')
  138. end
  139. else # => ####.####
  140. write(io, pdigits+0, pt)
  141. write(io, '.')
  142. write(io, pdigits+pt, len-pt)
  143. end
  144. nothing
  145. end
  146. print_shortest(io, x::Float64, dot::Bool) = _print_shortest(io, x, dot, SHORTEST)
  147. print_shortest(io, x::Float32, dot::Bool) = _print_shortest(io, x, dot, SHORTEST_SINGLE)
  148. print_shortest(io, x::Union(Float,Integer)) = print_shortest(io, float(x), false)
  149. end # module