dtoa.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. package goja
  2. // Ported from Rhino (https://github.com/mozilla/rhino/blob/master/src/org/mozilla/javascript/DToA.java)
  3. import (
  4. "bytes"
  5. "fmt"
  6. "math"
  7. "math/big"
  8. "strconv"
  9. )
  10. const (
  11. frac_mask = 0xfffff
  12. exp_shift = 20
  13. exp_msk1 = 0x100000
  14. exp_shiftL = 52
  15. exp_mask_shifted = 0x7ff
  16. frac_maskL = 0xfffffffffffff
  17. exp_msk1L = 0x10000000000000
  18. exp_shift1 = 20
  19. exp_mask = 0x7ff00000
  20. bias = 1023
  21. p = 53
  22. bndry_mask = 0xfffff
  23. log2P = 1
  24. digits = "0123456789abcdefghijklmnopqrstuvwxyz"
  25. )
  26. func lo0bits(x uint32) (k uint32) {
  27. if (x & 7) != 0 {
  28. if (x & 1) != 0 {
  29. return 0
  30. }
  31. if (x & 2) != 0 {
  32. return 1
  33. }
  34. return 2
  35. }
  36. if (x & 0xffff) == 0 {
  37. k = 16
  38. x >>= 16
  39. }
  40. if (x & 0xff) == 0 {
  41. k += 8
  42. x >>= 8
  43. }
  44. if (x & 0xf) == 0 {
  45. k += 4
  46. x >>= 4
  47. }
  48. if (x & 0x3) == 0 {
  49. k += 2
  50. x >>= 2
  51. }
  52. if (x & 1) == 0 {
  53. k++
  54. x >>= 1
  55. if (x & 1) == 0 {
  56. return 32
  57. }
  58. }
  59. return
  60. }
  61. func hi0bits(x uint32) (k uint32) {
  62. if (x & 0xffff0000) == 0 {
  63. k = 16
  64. x <<= 16
  65. }
  66. if (x & 0xff000000) == 0 {
  67. k += 8
  68. x <<= 8
  69. }
  70. if (x & 0xf0000000) == 0 {
  71. k += 4
  72. x <<= 4
  73. }
  74. if (x & 0xc0000000) == 0 {
  75. k += 2
  76. x <<= 2
  77. }
  78. if (x & 0x80000000) == 0 {
  79. k++
  80. if (x & 0x40000000) == 0 {
  81. return 32
  82. }
  83. }
  84. return
  85. }
  86. func stuffBits(bits []byte, offset int, val uint32) {
  87. bits[offset] = byte(val >> 24)
  88. bits[offset+1] = byte(val >> 16)
  89. bits[offset+2] = byte(val >> 8)
  90. bits[offset+3] = byte(val)
  91. }
  92. func d2b(d float64) (b *big.Int, e int32, bits uint32) {
  93. dBits := math.Float64bits(d)
  94. d0 := uint32(dBits >> 32)
  95. d1 := uint32(dBits)
  96. z := d0 & frac_mask
  97. d0 &= 0x7fffffff /* clear sign bit, which we ignore */
  98. var de, k, i uint32
  99. var dbl_bits []byte
  100. if de = (d0 >> exp_shift); de != 0 {
  101. z |= exp_msk1
  102. }
  103. y := d1
  104. if y != 0 {
  105. dbl_bits = make([]byte, 8)
  106. k = lo0bits(y)
  107. y >>= k
  108. if k != 0 {
  109. stuffBits(dbl_bits, 4, y|z<<(32-k))
  110. z >>= k
  111. } else {
  112. stuffBits(dbl_bits, 4, y)
  113. }
  114. stuffBits(dbl_bits, 0, z)
  115. if z != 0 {
  116. i = 2
  117. } else {
  118. i = 1
  119. }
  120. } else {
  121. dbl_bits = make([]byte, 4)
  122. k = lo0bits(z)
  123. z >>= k
  124. stuffBits(dbl_bits, 0, z)
  125. k += 32
  126. i = 1
  127. }
  128. if de != 0 {
  129. e = int32(de - bias - (p - 1) + k)
  130. bits = p - k
  131. } else {
  132. e = int32(de - bias - (p - 1) + 1 + k)
  133. bits = 32*i - hi0bits(z)
  134. }
  135. b = (&big.Int{}).SetBytes(dbl_bits)
  136. return
  137. }
  138. func dtobasestr(num float64, radix int) string {
  139. var negative bool
  140. if num < 0 {
  141. num = -num
  142. negative = true
  143. }
  144. dfloor := math.Floor(num)
  145. ldfloor := int64(dfloor)
  146. var intDigits string
  147. if dfloor == float64(ldfloor) {
  148. if negative {
  149. ldfloor = -ldfloor
  150. }
  151. intDigits = strconv.FormatInt(ldfloor, radix)
  152. } else {
  153. floorBits := math.Float64bits(num)
  154. exp := int(floorBits>>exp_shiftL) & exp_mask_shifted
  155. var mantissa int64
  156. if exp == 0 {
  157. mantissa = int64((floorBits & frac_maskL) << 1)
  158. } else {
  159. mantissa = int64((floorBits & frac_maskL) | exp_msk1L)
  160. }
  161. if negative {
  162. mantissa = -mantissa
  163. }
  164. exp -= 1075
  165. x := big.NewInt(mantissa)
  166. if exp > 0 {
  167. x.Lsh(x, uint(exp))
  168. } else if exp < 0 {
  169. x.Rsh(x, uint(-exp))
  170. }
  171. intDigits = x.Text(radix)
  172. }
  173. if num == dfloor {
  174. // No fraction part
  175. return intDigits
  176. } else {
  177. /* We have a fraction. */
  178. var buffer bytes.Buffer
  179. buffer.WriteString(intDigits)
  180. buffer.WriteByte('.')
  181. df := num - dfloor
  182. dBits := math.Float64bits(num)
  183. word0 := uint32(dBits >> 32)
  184. word1 := uint32(dBits)
  185. b, e, _ := d2b(df)
  186. // JS_ASSERT(e < 0);
  187. /* At this point df = b * 2^e. e must be less than zero because 0 < df < 1. */
  188. s2 := -int32((word0 >> exp_shift1) & (exp_mask >> exp_shift1))
  189. if s2 == 0 {
  190. s2 = -1
  191. }
  192. s2 += bias + p
  193. /* 1/2^s2 = (nextDouble(d) - d)/2 */
  194. // JS_ASSERT(-s2 < e);
  195. if -s2 >= e {
  196. panic(fmt.Errorf("-s2 >= e: %d, %d", -s2, e))
  197. }
  198. mlo := big.NewInt(1)
  199. mhi := mlo
  200. if (word1 == 0) && ((word0 & bndry_mask) == 0) && ((word0 & (exp_mask & exp_mask << 1)) != 0) {
  201. /* The special case. Here we want to be within a quarter of the last input
  202. significant digit instead of one half of it when the output string's value is less than d. */
  203. s2 += log2P
  204. mhi = big.NewInt(1 << log2P)
  205. }
  206. b.Lsh(b, uint(e+s2))
  207. s := big.NewInt(1)
  208. s.Lsh(s, uint(s2))
  209. /* At this point we have the following:
  210. * s = 2^s2;
  211. * 1 > df = b/2^s2 > 0;
  212. * (d - prevDouble(d))/2 = mlo/2^s2;
  213. * (nextDouble(d) - d)/2 = mhi/2^s2. */
  214. bigBase := big.NewInt(int64(radix))
  215. done := false
  216. m := &big.Int{}
  217. delta := &big.Int{}
  218. for !done {
  219. b.Mul(b, bigBase)
  220. b.DivMod(b, s, m)
  221. digit := byte(b.Int64())
  222. b, m = m, b
  223. mlo.Mul(mlo, bigBase)
  224. if mlo != mhi {
  225. mhi.Mul(mhi, bigBase)
  226. }
  227. /* Do we yet have the shortest string that will round to d? */
  228. j := b.Cmp(mlo)
  229. /* j is b/2^s2 compared with mlo/2^s2. */
  230. delta.Sub(s, mhi)
  231. var j1 int
  232. if delta.Sign() <= 0 {
  233. j1 = 1
  234. } else {
  235. j1 = b.Cmp(delta)
  236. }
  237. /* j1 is b/2^s2 compared with 1 - mhi/2^s2. */
  238. if j1 == 0 && (word1&1) == 0 {
  239. if j > 0 {
  240. digit++
  241. }
  242. done = true
  243. } else if j < 0 || (j == 0 && ((word1 & 1) == 0)) {
  244. if j1 > 0 {
  245. /* Either dig or dig+1 would work here as the least significant digit.
  246. Use whichever would produce an output value closer to d. */
  247. b.Lsh(b, 1)
  248. j1 = b.Cmp(s)
  249. if j1 > 0 { /* The even test (|| (j1 == 0 && (digit & 1))) is not here because it messes up odd base output such as 3.5 in base 3. */
  250. digit++
  251. }
  252. }
  253. done = true
  254. } else if j1 > 0 {
  255. digit++
  256. done = true
  257. }
  258. // JS_ASSERT(digit < (uint32)base);
  259. buffer.WriteByte(digits[digit])
  260. }
  261. return buffer.String()
  262. }
  263. }