float.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. package strconv // import "github.com/tdewolff/parse/strconv"
  2. import "math"
  3. var float64pow10 = []float64{
  4. 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
  5. 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
  6. 1e20, 1e21, 1e22,
  7. }
  8. // Float parses a byte-slice and returns the float it represents.
  9. // If an invalid character is encountered, it will stop there.
  10. func ParseFloat(b []byte) (float64, int) {
  11. i := 0
  12. neg := false
  13. if i < len(b) && (b[i] == '+' || b[i] == '-') {
  14. neg = b[i] == '-'
  15. i++
  16. }
  17. dot := -1
  18. trunk := -1
  19. n := uint64(0)
  20. for ; i < len(b); i++ {
  21. c := b[i]
  22. if c >= '0' && c <= '9' {
  23. if trunk == -1 {
  24. if n > math.MaxUint64/10 {
  25. trunk = i
  26. } else {
  27. n *= 10
  28. n += uint64(c - '0')
  29. }
  30. }
  31. } else if dot == -1 && c == '.' {
  32. dot = i
  33. } else {
  34. break
  35. }
  36. }
  37. f := float64(n)
  38. if neg {
  39. f = -f
  40. }
  41. mantExp := int64(0)
  42. if dot != -1 {
  43. if trunk == -1 {
  44. trunk = i
  45. }
  46. mantExp = int64(trunk - dot - 1)
  47. } else if trunk != -1 {
  48. mantExp = int64(trunk - i)
  49. }
  50. expExp := int64(0)
  51. if i < len(b) && (b[i] == 'e' || b[i] == 'E') {
  52. i++
  53. if e, expLen := ParseInt(b[i:]); expLen > 0 {
  54. expExp = e
  55. i += expLen
  56. }
  57. }
  58. exp := expExp - mantExp
  59. // copied from strconv/atof.go
  60. if exp == 0 {
  61. return f, i
  62. } else if exp > 0 && exp <= 15+22 { // int * 10^k
  63. // If exponent is big but number of digits is not,
  64. // can move a few zeros into the integer part.
  65. if exp > 22 {
  66. f *= float64pow10[exp-22]
  67. exp = 22
  68. }
  69. if f <= 1e15 && f >= -1e15 {
  70. return f * float64pow10[exp], i
  71. }
  72. } else if exp < 0 && exp >= -22 { // int / 10^k
  73. return f / float64pow10[-exp], i
  74. }
  75. f *= math.Pow10(int(-mantExp))
  76. return f * math.Pow10(int(expExp)), i
  77. }
  78. const log2 = 0.301029995
  79. const int64maxlen = 18
  80. func float64exp(f float64) int {
  81. exp2 := 0
  82. if f != 0.0 {
  83. x := math.Float64bits(f)
  84. exp2 = int(x>>(64-11-1))&0x7FF - 1023 + 1
  85. }
  86. exp10 := float64(exp2) * log2
  87. if exp10 < 0 {
  88. exp10 -= 1.0
  89. }
  90. return int(exp10)
  91. }
  92. func AppendFloat(b []byte, f float64, prec int) ([]byte, bool) {
  93. if math.IsNaN(f) || math.IsInf(f, 0) {
  94. return b, false
  95. } else if prec >= int64maxlen {
  96. return b, false
  97. }
  98. neg := false
  99. if f < 0.0 {
  100. f = -f
  101. neg = true
  102. }
  103. if prec == -1 {
  104. prec = int64maxlen - 1
  105. }
  106. prec -= float64exp(f) // number of digits in front of the dot
  107. f *= math.Pow10(prec)
  108. // calculate mantissa and exponent
  109. mant := int64(f)
  110. mantLen := LenInt(mant)
  111. mantExp := mantLen - prec - 1
  112. if mant == 0 {
  113. return append(b, '0'), true
  114. }
  115. // expLen is zero for positive exponents, because positive exponents are determined later on in the big conversion loop
  116. exp := 0
  117. expLen := 0
  118. if mantExp > 0 {
  119. // positive exponent is determined in the loop below
  120. // but if we initially decreased the exponent to fit in an integer, we can't set the new exponent in the loop alone,
  121. // since the number of zeros at the end determines the positive exponent in the loop, and we just artificially lost zeros
  122. if prec < 0 {
  123. exp = mantExp
  124. }
  125. expLen = 1 + LenInt(int64(exp)) // e + digits
  126. } else if mantExp < -3 {
  127. exp = mantExp
  128. expLen = 2 + LenInt(int64(exp)) // e + minus + digits
  129. } else if mantExp < -1 {
  130. mantLen += -mantExp - 1 // extra zero between dot and first digit
  131. }
  132. // reserve space in b
  133. i := len(b)
  134. maxLen := 1 + mantLen + expLen // dot + mantissa digits + exponent
  135. if neg {
  136. maxLen++
  137. }
  138. if i+maxLen > cap(b) {
  139. b = append(b, make([]byte, maxLen)...)
  140. } else {
  141. b = b[:i+maxLen]
  142. }
  143. // write to string representation
  144. if neg {
  145. b[i] = '-'
  146. i++
  147. }
  148. // big conversion loop, start at the end and move to the front
  149. // initially print trailing zeros and remove them later on
  150. // for example if the first non-zero digit is three positions in front of the dot, it will overwrite the zeros with a positive exponent
  151. zero := true
  152. last := i + mantLen // right-most position of digit that is non-zero + dot
  153. dot := last - prec - exp // position of dot
  154. j := last
  155. for mant > 0 {
  156. if j == dot {
  157. b[j] = '.'
  158. j--
  159. }
  160. newMant := mant / 10
  161. digit := mant - 10*newMant
  162. if zero && digit > 0 {
  163. // first non-zero digit, if we are still behind the dot we can trim the end to this position
  164. // otherwise trim to the dot (including the dot)
  165. if j > dot {
  166. i = j + 1
  167. // decrease negative exponent further to get rid of dot
  168. if exp < 0 {
  169. newExp := exp - (j - dot)
  170. // getting rid of the dot shouldn't lower the exponent to more digits (e.g. -9 -> -10)
  171. if LenInt(int64(newExp)) == LenInt(int64(exp)) {
  172. exp = newExp
  173. dot = j
  174. j--
  175. i--
  176. }
  177. }
  178. } else {
  179. i = dot
  180. }
  181. last = j
  182. zero = false
  183. }
  184. b[j] = '0' + byte(digit)
  185. j--
  186. mant = newMant
  187. }
  188. if j > dot {
  189. // extra zeros behind the dot
  190. for j > dot {
  191. b[j] = '0'
  192. j--
  193. }
  194. b[j] = '.'
  195. } else if last+3 < dot {
  196. // add positive exponent because we have 3 or more zeros in front of the dot
  197. i = last + 1
  198. exp = dot - last - 1
  199. } else if j == dot {
  200. // handle 0.1
  201. b[j] = '.'
  202. }
  203. // exponent
  204. if exp != 0 {
  205. if exp == 1 {
  206. b[i] = '0'
  207. i++
  208. } else if exp == 2 {
  209. b[i] = '0'
  210. b[i+1] = '0'
  211. i += 2
  212. } else {
  213. b[i] = 'e'
  214. i++
  215. if exp < 0 {
  216. b[i] = '-'
  217. i++
  218. exp = -exp
  219. }
  220. i += LenInt(int64(exp))
  221. j := i
  222. for exp > 0 {
  223. newExp := exp / 10
  224. digit := exp - 10*newExp
  225. j--
  226. b[j] = '0' + byte(digit)
  227. exp = newExp
  228. }
  229. }
  230. }
  231. return b[:i], true
  232. }