/base/ryu/fixed.jl

https://github.com/JuliaLang/julia · Julia · 182 lines · 177 code · 3 blank · 2 comment · 48 complexity · 97ea60d9e7abf8f826a2d920f119f5d1 MD5 · raw file

  1. function writefixed(buf, pos, v::T,
  2. precision=-1, plus=false, space=false, hash=false,
  3. decchar=UInt8('.'), trimtrailingzeros=false) where {T <: Base.IEEEFloat}
  4. @assert 0 < pos <= length(buf)
  5. startpos = pos
  6. x = Float64(v)
  7. pos = append_sign(x, plus, space, buf, pos)
  8. # special cases
  9. if x == 0
  10. buf[pos] = UInt8('0')
  11. pos += 1
  12. if precision > 0 && !trimtrailingzeros
  13. buf[pos] = decchar
  14. pos += 1
  15. for _ = 1:precision
  16. buf[pos] = UInt8('0')
  17. pos += 1
  18. end
  19. elseif hash
  20. buf[pos] = decchar
  21. pos += 1
  22. end
  23. return pos
  24. elseif isnan(x)
  25. buf[pos] = UInt8('N')
  26. buf[pos + 1] = UInt8('a')
  27. buf[pos + 2] = UInt8('N')
  28. return pos + 3
  29. elseif !isfinite(x)
  30. buf[pos] = UInt8('I')
  31. buf[pos + 1] = UInt8('n')
  32. buf[pos + 2] = UInt8('f')
  33. return pos + 3
  34. end
  35. bits = Core.bitcast(UInt64, x)
  36. mant = bits & MANTISSA_MASK
  37. exp = Int((bits >> 52) & EXP_MASK)
  38. if exp == 0
  39. e2 = 1 - 1023 - 52
  40. m2 = mant
  41. else
  42. e2 = exp - 1023 - 52
  43. m2 = (Int64(1) << 52) | mant
  44. end
  45. nonzero = false
  46. if e2 >= -52
  47. idx = e2 < 0 ? 0 : indexforexp(e2)
  48. p10bits = pow10bitsforindex(idx)
  49. len = lengthforindex(idx)
  50. i = len - 1
  51. while i >= 0
  52. j = p10bits - e2
  53. #=@inbounds=# mula, mulb, mulc = POW10_SPLIT[POW10_OFFSET[idx + 1] + i + 1]
  54. digits = mulshiftmod1e9(m2 << 8, mula, mulb, mulc, j + 8)
  55. if nonzero
  56. pos = append_nine_digits(digits, buf, pos)
  57. elseif digits != 0
  58. olength = decimallength(digits)
  59. pos = append_n_digits(olength, digits, buf, pos)
  60. nonzero = true
  61. end
  62. i -= 1
  63. end
  64. end
  65. if !nonzero
  66. buf[pos] = UInt8('0')
  67. pos += 1
  68. end
  69. hasfractional = false
  70. if precision > 0 || hash
  71. buf[pos] = decchar
  72. pos += 1
  73. hasfractional = true
  74. end
  75. if e2 < 0
  76. idx = div(-e2, 16)
  77. blocks = div(precision, 9) + 1
  78. roundUp = 0
  79. i = 0
  80. if blocks <= MIN_BLOCK_2[idx + 1]
  81. i = blocks
  82. for _ = 1:precision
  83. buf[pos] = UInt8('0')
  84. pos += 1
  85. end
  86. elseif i < MIN_BLOCK_2[idx + 1]
  87. i = MIN_BLOCK_2[idx + 1]
  88. for _ = 1:(9 * i)
  89. buf[pos] = UInt8('0')
  90. pos += 1
  91. end
  92. end
  93. while i < blocks
  94. j = 120 + (-e2 - 16 * idx)
  95. p = POW10_OFFSET_2[idx + 1] + UInt32(i) - MIN_BLOCK_2[idx + 1]
  96. if p >= POW10_OFFSET_2[idx + 2]
  97. for _ = 1:(precision - 9 * i)
  98. buf[pos] = UInt8('0')
  99. pos += 1
  100. end
  101. break
  102. end
  103. #=@inbounds=# mula, mulb, mulc = POW10_SPLIT_2[p + 1]
  104. digits = mulshiftmod1e9(m2 << 8, mula, mulb, mulc, j + 8)
  105. if i < blocks - 1
  106. pos = append_nine_digits(digits, buf, pos)
  107. else
  108. maximum = precision - 9 * i
  109. lastDigit = 0
  110. k = 0
  111. while k < 9 - maximum
  112. # global digits, lastDigit, k
  113. lastDigit = digits % 10
  114. digits = div(digits, 10)
  115. k += 1
  116. end
  117. if lastDigit != 5
  118. roundUp = lastDigit > 5
  119. else
  120. requiredTwos = -e2 - precision - 1
  121. trailingZeros = requiredTwos <= 0 || (requiredTwos < 60 && pow2(m2, requiredTwos))
  122. roundUp = trailingZeros ? 2 : 1
  123. end
  124. if maximum > 0
  125. pos = append_c_digits(maximum, digits, buf, pos)
  126. end
  127. break
  128. end
  129. i += 1
  130. end
  131. if roundUp != 0
  132. roundPos = pos
  133. dotPos = 1
  134. while true
  135. roundPos -= 1
  136. if roundPos == (startpos - 1) || (buf[roundPos] == UInt8('-')) || (plus && buf[roundPos] == UInt8('+')) || (space && buf[roundPos] == UInt8(' '))
  137. buf[roundPos + 1] = UInt8('1')
  138. if dotPos > 1
  139. buf[dotPos] = UInt8('0')
  140. buf[dotPos + 1] = decchar
  141. hasfractional = true
  142. end
  143. buf[pos] = UInt8('0')
  144. pos += 1
  145. break
  146. end
  147. c = roundPos > 0 ? buf[roundPos] : 0x00
  148. if c == decchar
  149. dotPos = roundPos
  150. continue
  151. elseif c == UInt8('9')
  152. buf[roundPos] = UInt8('0')
  153. roundUp = 1
  154. continue
  155. else
  156. if roundUp == 2 && UInt8(c) % 2 == 0
  157. break
  158. end
  159. buf[roundPos] = c + 1
  160. break
  161. end
  162. end
  163. end
  164. else
  165. for _ = 1:precision
  166. buf[pos] = UInt8('0')
  167. pos += 1
  168. end
  169. end
  170. if trimtrailingzeros && hasfractional
  171. while buf[pos - 1] == UInt8('0')
  172. pos -= 1
  173. end
  174. if buf[pos - 1] == decchar && !hash
  175. pos -= 1
  176. end
  177. end
  178. return pos
  179. end