float.go 5.6 KB

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