github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/ftoa/ftoa.go (about) 1 package ftoa 2 3 import ( 4 "math" 5 "math/big" 6 ) 7 8 const ( 9 exp_11 = 0x3ff00000 10 frac_mask1 = 0xfffff 11 bletch = 0x10 12 quick_max = 14 13 int_max = 14 14 ) 15 16 var ( 17 tens = [...]float64{ 18 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 19 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 20 1e20, 1e21, 1e22, 21 } 22 23 bigtens = [...]float64{1e16, 1e32, 1e64, 1e128, 1e256} 24 25 big5 = big.NewInt(5) 26 big10 = big.NewInt(10) 27 28 p05 = []*big.Int{big5, big.NewInt(25), big.NewInt(125)} 29 pow5Cache [7]*big.Int 30 31 dtoaModes = []int{ 32 ModeStandard: 0, 33 ModeStandardExponential: 0, 34 ModeFixed: 3, 35 ModeExponential: 2, 36 ModePrecision: 2, 37 } 38 ) 39 40 /* 41 d must be > 0 and must not be Inf 42 43 mode: 44 45 0 ==> shortest string that yields d when read in 46 and rounded to nearest. 47 1 ==> like 0, but with Steele & White stopping rule; 48 e.g. with IEEE P754 arithmetic , mode 0 gives 49 1e23 whereas mode 1 gives 9.999999999999999e22. 50 2 ==> max(1,ndigits) significant digits. This gives a 51 return value similar to that of ecvt, except 52 that trailing zeros are suppressed. 53 3 ==> through ndigits past the decimal point. This 54 gives a return value similar to that from fcvt, 55 except that trailing zeros are suppressed, and 56 ndigits can be negative. 57 4,5 ==> similar to 2 and 3, respectively, but (in 58 round-nearest mode) with the tests of mode 0 to 59 possibly return a shorter string that rounds to d. 60 With IEEE arithmetic and compilation with 61 -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same 62 as modes 2 and 3 when FLT_ROUNDS != 1. 63 6-9 ==> Debugging modes similar to mode - 4: don't try 64 fast floating-point estimate (if applicable). 65 66 Values of mode other than 0-9 are treated as mode 0. 67 */ 68 func ftoa(d float64, mode int, biasUp bool, ndigits int, buf []byte) ([]byte, int) { 69 startPos := len(buf) 70 dblBits := make([]byte, 0, 8) 71 be, bbits, dblBits := d2b(d, dblBits) 72 73 dBits := math.Float64bits(d) 74 word0 := uint32(dBits >> 32) 75 word1 := uint32(dBits) 76 77 i := int((word0 >> exp_shift1) & (exp_mask >> exp_shift1)) 78 var d2 float64 79 var denorm bool 80 if i != 0 { 81 d2 = setWord0(d, (word0&frac_mask1)|exp_11) 82 i -= bias 83 denorm = false 84 } else { 85 /* d is denormalized */ 86 i = bbits + be + (bias + (p - 1) - 1) 87 var x uint64 88 if i > 32 { 89 x = uint64(word0)<<(64-i) | uint64(word1)>>(i-32) 90 } else { 91 x = uint64(word1) << (32 - i) 92 } 93 d2 = setWord0(float64(x), uint32((x>>32)-31*exp_mask)) 94 i -= (bias + (p - 1) - 1) + 1 95 denorm = true 96 } 97 /* At this point d = f*2^i, where 1 <= f < 2. d2 is an approximation of f. */ 98 ds := (d2-1.5)*0.289529654602168 + 0.1760912590558 + float64(i)*0.301029995663981 99 k := int(ds) 100 if ds < 0.0 && ds != float64(k) { 101 k-- /* want k = floor(ds) */ 102 } 103 k_check := true 104 if k >= 0 && k < len(tens) { 105 if d < tens[k] { 106 k-- 107 } 108 k_check = false 109 } 110 /* At this point floor(log10(d)) <= k <= floor(log10(d))+1. 111 If k_check is zero, we're guaranteed that k = floor(log10(d)). */ 112 j := bbits - i - 1 113 var b2, s2, b5, s5 int 114 /* At this point d = b/2^j, where b is an odd integer. */ 115 if j >= 0 { 116 b2 = 0 117 s2 = j 118 } else { 119 b2 = -j 120 s2 = 0 121 } 122 if k >= 0 { 123 b5 = 0 124 s5 = k 125 s2 += k 126 } else { 127 b2 -= k 128 b5 = -k 129 s5 = 0 130 } 131 /* At this point d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5), where b is an odd integer, 132 b2 >= 0, b5 >= 0, s2 >= 0, and s5 >= 0. */ 133 if mode < 0 || mode > 9 { 134 mode = 0 135 } 136 try_quick := true 137 if mode > 5 { 138 mode -= 4 139 try_quick = false 140 } 141 leftright := true 142 var ilim, ilim1 int 143 switch mode { 144 case 0, 1: 145 ilim, ilim1 = -1, -1 146 ndigits = 0 147 case 2: 148 leftright = false 149 fallthrough 150 case 4: 151 if ndigits <= 0 { 152 ndigits = 1 153 } 154 ilim, ilim1 = ndigits, ndigits 155 case 3: 156 leftright = false 157 fallthrough 158 case 5: 159 i = ndigits + k + 1 160 ilim = i 161 ilim1 = i - 1 162 } 163 /* ilim is the maximum number of significant digits we want, based on k and ndigits. */ 164 /* ilim1 is the maximum number of significant digits we want, based on k and ndigits, 165 when it turns out that k was computed too high by one. */ 166 fast_failed := false 167 if ilim >= 0 && ilim <= quick_max && try_quick { 168 169 /* Try to get by with floating-point arithmetic. */ 170 171 i = 0 172 d2 = d 173 k0 := k 174 ilim0 := ilim 175 ieps := 2 /* conservative */ 176 /* Divide d by 10^k, keeping track of the roundoff error and avoiding overflows. */ 177 if k > 0 { 178 ds = tens[k&0xf] 179 j = k >> 4 180 if (j & bletch) != 0 { 181 /* prevent overflows */ 182 j &= bletch - 1 183 d /= bigtens[len(bigtens)-1] 184 ieps++ 185 } 186 for ; j != 0; i++ { 187 if (j & 1) != 0 { 188 ieps++ 189 ds *= bigtens[i] 190 } 191 j >>= 1 192 } 193 d /= ds 194 } else if j1 := -k; j1 != 0 { 195 d *= tens[j1&0xf] 196 for j = j1 >> 4; j != 0; i++ { 197 if (j & 1) != 0 { 198 ieps++ 199 d *= bigtens[i] 200 } 201 j >>= 1 202 } 203 } 204 /* Check that k was computed correctly. */ 205 if k_check && d < 1.0 && ilim > 0 { 206 if ilim1 <= 0 { 207 fast_failed = true 208 } else { 209 ilim = ilim1 210 k-- 211 d *= 10. 212 ieps++ 213 } 214 } 215 /* eps bounds the cumulative error. */ 216 eps := float64(ieps)*d + 7.0 217 eps = setWord0(eps, _word0(eps)-(p-1)*exp_msk1) 218 if ilim == 0 { 219 d -= 5.0 220 if d > eps { 221 buf = append(buf, '1') 222 k++ 223 return buf, k + 1 224 } 225 if d < -eps { 226 buf = append(buf, '0') 227 return buf, 1 228 } 229 fast_failed = true 230 } 231 if !fast_failed { 232 fast_failed = true 233 if leftright { 234 /* Use Steele & White method of only 235 * generating digits needed. 236 */ 237 eps = 0.5/tens[ilim-1] - eps 238 for i = 0; ; { 239 l := int64(d) 240 d -= float64(l) 241 buf = append(buf, byte('0'+l)) 242 if d < eps { 243 return buf, k + 1 244 } 245 if 1.0-d < eps { 246 buf, k = bumpUp(buf, k) 247 return buf, k + 1 248 } 249 i++ 250 if i >= ilim { 251 break 252 } 253 eps *= 10.0 254 d *= 10.0 255 } 256 } else { 257 /* Generate ilim digits, then fix them up. */ 258 eps *= tens[ilim-1] 259 for i = 1; ; i++ { 260 l := int64(d) 261 d -= float64(l) 262 buf = append(buf, byte('0'+l)) 263 if i == ilim { 264 if d > 0.5+eps { 265 buf, k = bumpUp(buf, k) 266 return buf, k + 1 267 } else if d < 0.5-eps { 268 buf = stripTrailingZeroes(buf, startPos) 269 return buf, k + 1 270 } 271 break 272 } 273 d *= 10.0 274 } 275 } 276 } 277 if fast_failed { 278 buf = buf[:startPos] 279 d = d2 280 k = k0 281 ilim = ilim0 282 } 283 } 284 285 /* Do we have a "small" integer? */ 286 if be >= 0 && k <= int_max { 287 /* Yes. */ 288 ds = tens[k] 289 if ndigits < 0 && ilim <= 0 { 290 if ilim < 0 || d < 5*ds || (!biasUp && d == 5*ds) { 291 buf = buf[:startPos] 292 buf = append(buf, '0') 293 return buf, 1 294 } 295 buf = append(buf, '1') 296 k++ 297 return buf, k + 1 298 } 299 for i = 1; ; i++ { 300 l := int64(d / ds) 301 d -= float64(l) * ds 302 buf = append(buf, byte('0'+l)) 303 if i == ilim { 304 d += d 305 if (d > ds) || (d == ds && (((l & 1) != 0) || biasUp)) { 306 buf, k = bumpUp(buf, k) 307 } 308 break 309 } 310 d *= 10.0 311 if d == 0 { 312 break 313 } 314 } 315 return buf, k + 1 316 } 317 318 m2 := b2 319 m5 := b5 320 var mhi, mlo *big.Int 321 if leftright { 322 if mode < 2 { 323 if denorm { 324 i = be + (bias + (p - 1) - 1 + 1) 325 } else { 326 i = 1 + p - bbits 327 } 328 /* i is 1 plus the number of trailing zero bits in d's significand. Thus, 329 (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 lsb of d)/10^k. */ 330 } else { 331 j = ilim - 1 332 if m5 >= j { 333 m5 -= j 334 } else { 335 j -= m5 336 s5 += j 337 b5 += j 338 m5 = 0 339 } 340 i = ilim 341 if i < 0 { 342 m2 -= i 343 i = 0 344 } 345 /* (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 * 10^(1-ilim))/10^k. */ 346 } 347 b2 += i 348 s2 += i 349 mhi = big.NewInt(1) 350 /* (mhi * 2^m2 * 5^m5) / (2^s2 * 5^s5) = one-half of last printed (when mode >= 2) or 351 input (when mode < 2) significant digit, divided by 10^k. */ 352 } 353 354 /* We still have d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5). Reduce common factors in 355 b2, m2, and s2 without changing the equalities. */ 356 if m2 > 0 && s2 > 0 { 357 if m2 < s2 { 358 i = m2 359 } else { 360 i = s2 361 } 362 b2 -= i 363 m2 -= i 364 s2 -= i 365 } 366 367 b := new(big.Int).SetBytes(dblBits) 368 /* Fold b5 into b and m5 into mhi. */ 369 if b5 > 0 { 370 if leftright { 371 if m5 > 0 { 372 pow5mult(mhi, m5) 373 b.Mul(mhi, b) 374 } 375 j = b5 - m5 376 if j != 0 { 377 pow5mult(b, j) 378 } 379 } else { 380 pow5mult(b, b5) 381 } 382 } 383 /* Now we have d/10^k = (b * 2^b2) / (2^s2 * 5^s5) and 384 (mhi * 2^m2) / (2^s2 * 5^s5) = one-half of last printed or input significant digit, divided by 10^k. */ 385 386 S := big.NewInt(1) 387 if s5 > 0 { 388 pow5mult(S, s5) 389 } 390 /* Now we have d/10^k = (b * 2^b2) / (S * 2^s2) and 391 (mhi * 2^m2) / (S * 2^s2) = one-half of last printed or input significant digit, divided by 10^k. */ 392 393 /* Check for special case that d is a normalized power of 2. */ 394 spec_case := false 395 if mode < 2 { 396 if (_word1(d) == 0) && ((_word0(d) & bndry_mask) == 0) && 397 ((_word0(d) & (exp_mask & (exp_mask << 1))) != 0) { 398 /* The special case. Here we want to be within a quarter of the last input 399 significant digit instead of one half of it when the decimal output string's value is less than d. */ 400 b2 += log2P 401 s2 += log2P 402 spec_case = true 403 } 404 } 405 406 /* Arrange for convenient computation of quotients: 407 * shift left if necessary so divisor has 4 leading 0 bits. 408 * 409 * Perhaps we should just compute leading 28 bits of S once 410 * and for all and pass them and a shift to quorem, so it 411 * can do shifts and ors to compute the numerator for q. 412 */ 413 var zz int 414 if s5 != 0 { 415 S_bytes := S.Bytes() 416 var S_hiWord uint32 417 for idx := 0; idx < 4; idx++ { 418 S_hiWord = S_hiWord << 8 419 if idx < len(S_bytes) { 420 S_hiWord |= uint32(S_bytes[idx]) 421 } 422 } 423 zz = 32 - hi0bits(S_hiWord) 424 } else { 425 zz = 1 426 } 427 i = (zz + s2) & 0x1f 428 if i != 0 { 429 i = 32 - i 430 } 431 /* i is the number of leading zero bits in the most significant word of S*2^s2. */ 432 if i > 4 { 433 i -= 4 434 b2 += i 435 m2 += i 436 s2 += i 437 } else if i < 4 { 438 i += 28 439 b2 += i 440 m2 += i 441 s2 += i 442 } 443 /* Now S*2^s2 has exactly four leading zero bits in its most significant word. */ 444 if b2 > 0 { 445 b = b.Lsh(b, uint(b2)) 446 } 447 if s2 > 0 { 448 S.Lsh(S, uint(s2)) 449 } 450 /* Now we have d/10^k = b/S and 451 (mhi * 2^m2) / S = maximum acceptable error, divided by 10^k. */ 452 if k_check { 453 if b.Cmp(S) < 0 { 454 k-- 455 b.Mul(b, big10) /* we botched the k estimate */ 456 if leftright { 457 mhi.Mul(mhi, big10) 458 } 459 ilim = ilim1 460 } 461 } 462 /* At this point 1 <= d/10^k = b/S < 10. */ 463 464 if ilim <= 0 && mode > 2 { 465 /* We're doing fixed-mode output and d is less than the minimum nonzero output in this mode. 466 Output either zero or the minimum nonzero output depending on which is closer to d. */ 467 if ilim >= 0 { 468 i = b.Cmp(S.Mul(S, big5)) 469 } 470 if ilim < 0 || i < 0 || i == 0 && !biasUp { 471 /* Always emit at least one digit. If the number appears to be zero 472 using the current mode, then emit one '0' digit and set decpt to 1. */ 473 buf = buf[:startPos] 474 buf = append(buf, '0') 475 return buf, 1 476 } 477 buf = append(buf, '1') 478 k++ 479 return buf, k + 1 480 } 481 482 var dig byte 483 if leftright { 484 if m2 > 0 { 485 mhi.Lsh(mhi, uint(m2)) 486 } 487 488 /* Compute mlo -- check for special case 489 * that d is a normalized power of 2. 490 */ 491 492 mlo = mhi 493 if spec_case { 494 mhi = mlo 495 mhi = new(big.Int).Lsh(mhi, log2P) 496 } 497 /* mlo/S = maximum acceptable error, divided by 10^k, if the output is less than d. */ 498 /* mhi/S = maximum acceptable error, divided by 10^k, if the output is greater than d. */ 499 var z, delta big.Int 500 for i = 1; ; i++ { 501 z.DivMod(b, S, b) 502 dig = byte(z.Int64() + '0') 503 /* Do we yet have the shortest decimal string 504 * that will round to d? 505 */ 506 j = b.Cmp(mlo) 507 /* j is b/S compared with mlo/S. */ 508 delta.Sub(S, mhi) 509 var j1 int 510 if delta.Sign() <= 0 { 511 j1 = 1 512 } else { 513 j1 = b.Cmp(&delta) 514 } 515 /* j1 is b/S compared with 1 - mhi/S. */ 516 if (j1 == 0) && (mode == 0) && ((_word1(d) & 1) == 0) { 517 if dig == '9' { 518 var flag bool 519 buf = append(buf, '9') 520 if buf, flag = roundOff(buf, startPos); flag { 521 k++ 522 buf = append(buf, '1') 523 } 524 return buf, k + 1 525 } 526 if j > 0 { 527 dig++ 528 } 529 buf = append(buf, dig) 530 return buf, k + 1 531 } 532 if (j < 0) || ((j == 0) && (mode == 0) && ((_word1(d) & 1) == 0)) { 533 if j1 > 0 { 534 /* Either dig or dig+1 would work here as the least significant decimal digit. 535 Use whichever would produce a decimal value closer to d. */ 536 b.Lsh(b, 1) 537 j1 = b.Cmp(S) 538 if (j1 > 0) || (j1 == 0 && (((dig & 1) == 1) || biasUp)) { 539 dig++ 540 if dig == '9' { 541 buf = append(buf, '9') 542 buf, flag := roundOff(buf, startPos) 543 if flag { 544 k++ 545 buf = append(buf, '1') 546 } 547 return buf, k + 1 548 } 549 } 550 } 551 buf = append(buf, dig) 552 return buf, k + 1 553 } 554 if j1 > 0 { 555 if dig == '9' { /* possible if i == 1 */ 556 buf = append(buf, '9') 557 buf, flag := roundOff(buf, startPos) 558 if flag { 559 k++ 560 buf = append(buf, '1') 561 } 562 return buf, k + 1 563 } 564 buf = append(buf, dig+1) 565 return buf, k + 1 566 } 567 buf = append(buf, dig) 568 if i == ilim { 569 break 570 } 571 b.Mul(b, big10) 572 if mlo == mhi { 573 mhi.Mul(mhi, big10) 574 } else { 575 mlo.Mul(mlo, big10) 576 mhi.Mul(mhi, big10) 577 } 578 } 579 } else { 580 var z big.Int 581 for i = 1; ; i++ { 582 z.DivMod(b, S, b) 583 dig = byte(z.Int64() + '0') 584 buf = append(buf, dig) 585 if i >= ilim { 586 break 587 } 588 589 b.Mul(b, big10) 590 } 591 } 592 /* Round off last digit */ 593 594 b.Lsh(b, 1) 595 j = b.Cmp(S) 596 if (j > 0) || (j == 0 && (((dig & 1) == 1) || biasUp)) { 597 var flag bool 598 buf, flag = roundOff(buf, startPos) 599 if flag { 600 k++ 601 buf = append(buf, '1') 602 return buf, k + 1 603 } 604 } else { 605 buf = stripTrailingZeroes(buf, startPos) 606 } 607 608 return buf, k + 1 609 } 610 611 func bumpUp(buf []byte, k int) ([]byte, int) { 612 var lastCh byte 613 stop := 0 614 if len(buf) > 0 && buf[0] == '-' { 615 stop = 1 616 } 617 for { 618 lastCh = buf[len(buf)-1] 619 buf = buf[:len(buf)-1] 620 if lastCh != '9' { 621 break 622 } 623 if len(buf) == stop { 624 k++ 625 lastCh = '0' 626 break 627 } 628 } 629 buf = append(buf, lastCh+1) 630 return buf, k 631 } 632 633 func setWord0(d float64, w uint32) float64 { 634 dBits := math.Float64bits(d) 635 return math.Float64frombits(uint64(w)<<32 | dBits&0xffffffff) 636 } 637 638 func _word0(d float64) uint32 { 639 dBits := math.Float64bits(d) 640 return uint32(dBits >> 32) 641 } 642 643 func _word1(d float64) uint32 { 644 dBits := math.Float64bits(d) 645 return uint32(dBits) 646 } 647 648 func stripTrailingZeroes(buf []byte, startPos int) []byte { 649 bl := len(buf) - 1 650 for bl >= startPos && buf[bl] == '0' { 651 bl-- 652 } 653 return buf[:bl+1] 654 } 655 656 /* Set b = b * 5^k. k must be nonnegative. */ 657 func pow5mult(b *big.Int, k int) *big.Int { 658 if k < (1 << (len(pow5Cache) + 2)) { 659 i := k & 3 660 if i != 0 { 661 b.Mul(b, p05[i-1]) 662 } 663 k >>= 2 664 i = 0 665 for { 666 if k&1 != 0 { 667 b.Mul(b, pow5Cache[i]) 668 } 669 k >>= 1 670 if k == 0 { 671 break 672 } 673 i++ 674 } 675 return b 676 } 677 return b.Mul(b, new(big.Int).Exp(big5, big.NewInt(int64(k)), nil)) 678 } 679 680 func roundOff(buf []byte, startPos int) ([]byte, bool) { 681 i := len(buf) 682 for i != startPos { 683 i-- 684 if buf[i] != '9' { 685 buf[i]++ 686 return buf[:i+1], false 687 } 688 } 689 return buf[:startPos], true 690 } 691 692 func init() { 693 p := big.NewInt(625) 694 pow5Cache[0] = p 695 for i := 1; i < len(pow5Cache); i++ { 696 p = new(big.Int).Mul(p, p) 697 pow5Cache[i] = p 698 } 699 }