docs: static int
      JS_dtoa(double d, int mode, boolean biasUp, int ndigits,
                      boolean[] sign, StringBuilder buf)
      {
          /*  Arguments ndigits, decpt, sign are similar to those
              of ecvt and fcvt; trailing zeros are suppressed from
              the returned string.  If not null, *rve is set to point
              to the end of the return value.  If d is +-Infinity or NaN,
              then *decpt is set to 9999.
  
              mode:
              0 ==> shortest string that yields d when read in
              and rounded to nearest.
              1 ==> like 0, but with Steele & White stopping rule;
              e.g. with IEEE P754 arithmetic , mode 0 gives
              1e23 whereas mode 1 gives 9.999999999999999e22.
              2 ==> max(1,ndigits) significant digits.  This gives a
              return value similar to that of ecvt, except
              that trailing zeros are suppressed.
              3 ==> through ndigits past the decimal point.  This
              gives a return value similar to that from fcvt,
              except that trailing zeros are suppressed, and
              ndigits can be negative.
              4-9 should give the same return values as 2-3, i.e.,
              4 <= mode <= 9 ==> same return as mode
              2 + (mode & 1).  These modes are mainly for
              debugging; often they run slower but sometimes
              faster than modes 2-3.
              4,5,8,9 ==> left-to-right digit generation.
              6-9 ==> don't try fast floating-point estimate
              (if applicable).
  
              Values of mode other than 0-9 are treated as mode 0.
  
              Sufficient space is allocated to the return value
              to hold the suppressed trailing zeros.
          */
  
          int b2, b5, i, ieps, ilim, ilim0, ilim1,
              j, j1, k, k0, m2, m5, s2, s5;
          char dig;
          long L;
          long x;
          BigInteger b, b1, delta, mlo, mhi, S;
          int[] be = new int[1];
          int[] bbits = new int[1];
          double d2, ds, eps;
          boolean spec_case, denorm, k_check, try_quick, leftright;
  
          if ((word0(d) & Sign_bit) != 0) {
              /* set sign for everything, including 0's and NaNs */
              sign[0] = true;
              // word0(d) &= ~Sign_bit;  /* clear sign bit */
              d = setWord0(d, word0(d) & ~Sign_bit);
          }
          else
              sign[0] = false;
  
          if ((word0(d) & Exp_mask) == Exp_mask) {
              /* Infinity or NaN */
              buf.append(((word1(d) == 0) && ((word0(d) & Frac_mask) == 0)) ? "Infinity" : "NaN");
              return 9999;
          }
          if (d == 0) {
  //          no_digits:
              buf.setLength(0);
              buf.append('0');        /* copy "0" to buffer */
              return 1;
          }
  
          b = d2b(d, be, bbits);
          if ((i = (word0(d) >>> Exp_shift1 & (Exp_mask>>Exp_shift1))) != 0) {
              d2 = setWord0(d, (word0(d) & Frac_mask1) | Exp_11);
              /* log(x)   ~=~ log(1.5) + (x-1.5)/1.5
               * log10(x)  =  log(x) / log(10)
               *      ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
               * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)
               *
               * This suggests computing an approximation k to log10(d) by
               *
               * k = (i - Bias)*0.301029995663981
               *  + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
               *
               * We want k to be too large rather than too small.
               * The error in the first-order Taylor series approximation
               * is in our favor, so we just round up the constant enough
               * to compensate for any error in the multiplication of
               * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
               * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
               * adding 1e-13 to the constant term more than suffices.
               * Hence we adjust the constant term to 0.1760912590558.
               * (We could get a more accurate k by invoking log10,
               *  but this is probably not worthwhile.)
               */
              i -= Bias;
              denorm = false;
          }
          else {
              /* d is denormalized */
              i = bbits[0] + be[0] + (Bias + (P-1) - 1);
              x = (i > 32)
                      ? ((long) word0(d)) << (64 - i) | word1(d) >>> (i - 32)
                      : ((long) word1(d)) << (32 - i);
  //            d2 = x;
  //            word0(d2) -= 31*Exp_msk1; /* adjust exponent */
              d2 = setWord0(x, word0(x) - 31*Exp_msk1);
              i -= (Bias + (P-1) - 1) + 1;
              denorm = true;
          }
          /* At this point d = f*2^i, where 1 <= f < 2.  d2 is an approximation of f. */
          ds = (d2-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
          k = (int)ds;
          if (ds < 0.0 && ds != k)
              k--;    /* want k = floor(ds) */
          k_check = true;
          if (k >= 0 && k <= Ten_pmax) {
              if (d < tens[k])
                  k--;
              k_check = false;
          }
          /* At this point floor(log10(d)) <= k <= floor(log10(d))+1.
             If k_check is zero, we're guaranteed that k = floor(log10(d)). */
          j = bbits[0] - i - 1;
          /* At this point d = b/2^j, where b is an odd integer. */
          if (j >= 0) {
              b2 = 0;
              s2 = j;
          }
          else {
              b2 = -j;
              s2 = 0;
          }
          if (k >= 0) {
              b5 = 0;
              s5 = k;
              s2 += k;
          }
          else {
              b2 -= k;
              b5 = -k;
              s5 = 0;
          }
          /* At this point d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5), where b is an odd integer,
             b2 >= 0, b5 >= 0, s2 >= 0, and s5 >= 0. */
          if (mode < 0 || mode > 9)
              mode = 0;
          try_quick = true;
          if (mode > 5) {
              mode -= 4;
              try_quick = false;
          }
          leftright = true;
          ilim = ilim1 = 0;
          switch(mode) {
              case 0:
              case 1:
                  ilim = ilim1 = -1;
                  i = 18;
                  ndigits = 0;
                  break;
              case 2:
                  leftright = false;
                  /* fallthru */
              case 4:
                  if (ndigits <= 0)
                      ndigits = 1;
                  ilim = ilim1 = i = ndigits;
                  break;
              case 3:
                  leftright = false;
                  /* fallthru */
              case 5:
                  i = ndigits + k + 1;
                  ilim = i;
                  ilim1 = i - 1;
                  if (i <= 0)
                      i = 1;
          }
          /* ilim is the maximum number of significant digits we want, based on k and ndigits. */
          /* ilim1 is the maximum number of significant digits we want, based on k and ndigits,
             when it turns out that k was computed too high by one. */
  
          boolean fast_failed = false;
          if (ilim >= 0 && ilim <= Quick_max && try_quick) {
  
              /* Try to get by with floating-point arithmetic. */
  
              i = 0;
              d2 = d;
              k0 = k;
              ilim0 = ilim;
              ieps = 2; /* conservative */
              /* Divide d by 10^k, keeping track of the roundoff error and avoiding overflows. */
              if (k > 0) {
                  ds = tens[k&0xf];
                  j = k >> 4;
                  if ((j & Bletch) != 0) {
                      /* prevent overflows */
                      j &= Bletch - 1;
                      d /= bigtens[n_bigtens-1];
                      ieps++;
                  }
                  for(; (j != 0); j >>= 1, i++)
                      if ((j & 1) != 0) {
                          ieps++;
                          ds *= bigtens[i];
                      }
                  d /= ds;
              }
              else if ((j1 = -k) != 0) {
                  d *= tens[j1 & 0xf];
                  for(j = j1 >> 4; (j != 0); j >>= 1, i++)
                      if ((j & 1) != 0) {
                          ieps++;
                          d *= bigtens[i];
                      }
              }
              /* Check that k was computed correctly. */
              if (k_check && d < 1.0 && ilim > 0) {
                  if (ilim1 <= 0)
                      fast_failed = true;
                  else {
                      ilim = ilim1;
                      k--;
                      d *= 10.;
                      ieps++;
                  }
              }
              /* eps bounds the cumulative error. */
  //            eps = ieps*d + 7.0;
  //            word0(eps) -= (P-1)*Exp_msk1;
              eps = ieps*d + 7.0;
              eps = setWord0(eps, word0(eps) - (P-1)*Exp_msk1);
              if (ilim == 0) {
                  S = mhi = null;
                  d -= 5.0;
                  if (d > eps) {
                      buf.append('1');
                      k++;
                      return k + 1;
                  }
                  if (d < -eps) {
                      buf.setLength(0);
                      buf.append('0');        /* copy "0" to buffer */
                      return 1;
                  }
                  fast_failed = true;
              }
              if (!fast_failed) {
                  fast_failed = true;
                  if (leftright) {
                      /* Use Steele & White method of only
                       * generating digits needed.
                       */
                      eps = 0.5/tens[ilim-1] - eps;
                      for(i = 0;;) {
                          L = (long)d;
                          d -= L;
                          buf.append((char)('0' + L));
                          if (d < eps) {
                              return k + 1;
                          }
                          if (1.0 - d < eps) {
  //                            goto bump_up;
                                  char lastCh;
                                  while (true) {
                                      lastCh = buf.charAt(buf.length() - 1);
                                      buf.setLength(buf.length() - 1);
                                      if (lastCh != '9') break;
                                      if (buf.length() == 0) {
                                          k++;
                                          lastCh = '0';
                                          break;
                                      }
                                  }
                                  buf.append((char)(lastCh + 1));
                                  return k + 1;
                          }
                          if (++i >= ilim)
                              break;
                          eps *= 10.0;
                          d *= 10.0;
                      }
                  }
                  else {
                      /* Generate ilim digits, then fix them up. */
                      eps *= tens[ilim-1];
                      for(i = 1;; i++, d *= 10.0) {
                          L = (long)d;
                          d -= L;
                          buf.append((char)('0' + L));
                          if (i == ilim) {
                              if (d > 0.5 + eps) {
  //                                goto bump_up;
                                  char lastCh;
                                  while (true) {
                                      lastCh = buf.charAt(buf.length() - 1);
                                      buf.setLength(buf.length() - 1);
                                      if (lastCh != '9') break;
                                      if (buf.length() == 0) {
                                          k++;
                                          lastCh = '0';
                                          break;
                                      }
                                  }
                                  buf.append((char)(lastCh + 1));
                                  return k + 1;
                              }
                              else
                                  if (d < 0.5 - eps) {
                                      stripTrailingZeroes(buf);
  //                                    while(*--s == '0') ;
  //                                    s++;
                                      return k + 1;
                                  }
                              break;
                          }
                      }
                  }
              }
              if (fast_failed) {
                  buf.setLength(0);
                  d = d2;
                  k = k0;
                  ilim = ilim0;
              }
          }
  
          /* Do we have a "small" integer? */
  
          if (be[0] >= 0 && k <= Int_max) {
              /* Yes. */
              ds = tens[k];
              if (ndigits < 0 && ilim <= 0) {
                  S = mhi = null;
                  if (ilim < 0 || d < 5*ds || (!biasUp && d == 5*ds)) {
                      buf.setLength(0);
                      buf.append('0');        /* copy "0" to buffer */
                      return 1;
                  }
                  buf.append('1');
                  k++;
                  return k + 1;
              }
              for(i = 1;; i++) {
                  L = (long) (d / ds);
                  d -= L*ds;
                  buf.append((char)('0' + L));
                  if (i == ilim) {
                      d += d;
                      if ((d > ds) || (d == ds && (((L & 1) != 0) || biasUp))) {
  //                    bump_up:
  //                        while(*--s == '9')
  //                            if (s == buf) {
  //                                k++;
  //                                *s = '0';
  //                                break;
  //                            }
  //                        ++*s++;
                          char lastCh;
                          while (true) {
                              lastCh = buf.charAt(buf.length() - 1);
                              buf.setLength(buf.length() - 1);
                              if (lastCh != '9') break;
                              if (buf.length() == 0) {
                                  k++;
                                  lastCh = '0';
                                  break;
                              }
                          }
                          buf.append((char)(lastCh + 1));
                      }
                      break;
                  }
                  d *= 10.0;
                  if (d == 0)
                      break;
              }
              return k + 1;
          }
  
          m2 = b2;
          m5 = b5;
          mhi = mlo = null;
          if (leftright) {
              if (mode < 2) {
                  i = (denorm) ? be[0] + (Bias + (P-1) - 1 + 1) : 1 + P - bbits[0];
                  /* i is 1 plus the number of trailing zero bits in d's significand. Thus,
                     (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 lsb of d)/10^k. */
              }
              else {
                  j = ilim - 1;
                  if (m5 >= j)
                      m5 -= j;
                  else {
                      s5 += j -= m5;
                      b5 += j;
                      m5 = 0;
                  }
                  if ((i = ilim) < 0) {
                      m2 -= i;
                      i = 0;
                  }
                  /* (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 * 10^(1-ilim))/10^k. */
              }
              b2 += i;
              s2 += i;
              mhi = BigInteger.valueOf(1);
              /* (mhi * 2^m2 * 5^m5) / (2^s2 * 5^s5) = one-half of last printed (when mode >= 2) or
                 input (when mode < 2) significant digit, divided by 10^k. */
          }
          /* We still have d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5).  Reduce common factors in
             b2, m2, and s2 without changing the equalities. */
          if (m2 > 0 && s2 > 0) {
              i = (m2 < s2) ? m2 : s2;
              b2 -= i;
              m2 -= i;
              s2 -= i;
          }
  
          /* Fold b5 into b and m5 into mhi. */
          if (b5 > 0) {
              if (leftright) {
                  if (m5 > 0) {
                      mhi = pow5mult(mhi, m5);
                      b1 = mhi.multiply(b);
                      b = b1;
                  }
                  if ((j = b5 - m5) != 0)
                      b = pow5mult(b, j);
              }
              else
                  b = pow5mult(b, b5);
          }
          /* Now we have d/10^k = (b * 2^b2) / (2^s2 * 5^s5) and
             (mhi * 2^m2) / (2^s2 * 5^s5) = one-half of last printed or input significant digit, divided by 10^k. */
  
          S = BigInteger.valueOf(1);
          if (s5 > 0)
              S = pow5mult(S, s5);
          /* Now we have d/10^k = (b * 2^b2) / (S * 2^s2) and
             (mhi * 2^m2) / (S * 2^s2) = one-half of last printed or input significant digit, divided by 10^k. */
  
          /* Check for special case that d is a normalized power of 2. */
          spec_case = false;
          if (mode < 2) {
              if ( (word1(d) == 0) && ((word0(d) & Bndry_mask) == 0)
                  && ((word0(d) & (Exp_mask & Exp_mask << 1)) != 0)
                  ) {
                  /* The special case.  Here we want to be within a quarter of the last input
                     significant digit instead of one half of it when the decimal output string's value is less than d.  */
                  b2 += Log2P;
                  s2 += Log2P;
                  spec_case = true;
              }
          }
  
          /* Arrange for convenient computation of quotients:
           * shift left if necessary so divisor has 4 leading 0 bits.
           *
           * Perhaps we should just compute leading 28 bits of S once
           * and for all and pass them and a shift to quorem, so it
           * can do shifts and ors to compute the numerator for q.
           */
          byte [] S_bytes = S.toByteArray();
          int S_hiWord = 0;
          for (int idx = 0; idx < 4; idx++) {
              S_hiWord = (S_hiWord << 8);
              if (idx < S_bytes.length)
                  S_hiWord |= (S_bytes[idx] & 0xFF);
          }
          if ((i = (((s5 != 0) ? 32 - hi0bits(S_hiWord) : 1) + s2) & 0x1f) != 0)
              i = 32 - i;
          /* i is the number of leading zero bits in the most significant word of S*2^s2. */
          if (i > 4) {
              i -= 4;
              b2 += i;
              m2 += i;
              s2 += i;
          }
          else if (i < 4) {
              i += 28;
              b2 += i;
              m2 += i;
              s2 += i;
          }
          /* Now S*2^s2 has exactly four leading zero bits in its most significant word. */
          if (b2 > 0)
              b = b.shiftLeft(b2);
          if (s2 > 0)
              S = S.shiftLeft(s2);
          /* Now we have d/10^k = b/S and
             (mhi * 2^m2) / S = maximum acceptable error, divided by 10^k. */
          if (k_check) {
              if (b.compareTo(S) < 0) {
                  k--;
                  b = b.multiply(BigInteger.valueOf(10));  /* we botched the k estimate */
                  if (leftright)
                      mhi = mhi.multiply(BigInteger.valueOf(10));
                  ilim = ilim1;
              }
          }
          /* At this point 1 <= d/10^k = b/S < 10. */
  
          if (ilim <= 0 && mode > 2) {
              /* We're doing fixed-mode output and d is less than the minimum nonzero output in this mode.
                 Output either zero or the minimum nonzero output depending on which is closer to d. */
              if ((ilim < 0 )
                      || ((i = b.compareTo(S = S.multiply(BigInteger.valueOf(5)))) < 0)
                      || ((i == 0 && !biasUp))) {
              /* Always emit at least one digit.  If the number appears to be zero
                 using the current mode, then emit one '0' digit and set decpt to 1. */
              /*no_digits:
                  k = -1 - ndigits;
                  goto ret; */
                  buf.setLength(0);
                  buf.append('0');        /* copy "0" to buffer */
                  return 1;
  //                goto no_digits;
              }
  //        one_digit:
              buf.append('1');
              k++;
              return k + 1;
          }
          if (leftright) {
              if (m2 > 0)
                  mhi = mhi.shiftLeft(m2);
  
              /* Compute mlo -- check for special case
               * that d is a normalized power of 2.
               */
  
              mlo = mhi;
              if (spec_case) {
                  mhi = mlo;
                  mhi = mhi.shiftLeft(Log2P);
              }
              /* mlo/S = maximum acceptable error, divided by 10^k, if the output is less than d. */
              /* mhi/S = maximum acceptable error, divided by 10^k, if the output is greater than d. */
  
              for(i = 1;;i++) {
                  BigInteger[] divResult = b.divideAndRemainder(S);
                  b = divResult[1];
                  dig = (char)(divResult[0].intValue() + '0');
                  /* Do we yet have the shortest decimal string
                   * that will round to d?
                   */
                  j = b.compareTo(mlo);
                  /* j is b/S compared with mlo/S. */
                  delta = S.subtract(mhi);
                  j1 = (delta.signum() <= 0) ? 1 : b.compareTo(delta);
                  /* j1 is b/S compared with 1 - mhi/S. */
                  if ((j1 == 0) && (mode == 0) && ((word1(d) & 1) == 0)) {
                      if (dig == '9') {
                          buf.append('9');
                          if (roundOff(buf)) {
                              k++;
                              buf.append('1');
                          }
                          return k + 1;
  //                        goto round_9_up;
                      }
                      if (j > 0)
                          dig++;
                      buf.append(dig);
                      return k + 1;
                  }
                  if ((j < 0)
                          || ((j == 0)
                              && (mode == 0)
                              && ((word1(d) & 1) == 0)
                      )) {
                      if (j1 > 0) {
                          /* Either dig or dig+1 would work here as the least significant decimal digit.
                             Use whichever would produce a decimal value closer to d. */
                          b = b.shiftLeft(1);
                          j1 = b.compareTo(S);
                          if (((j1 > 0) || (j1 == 0 && (((dig & 1) == 1) || biasUp)))
                              && (dig++ == '9')) {
                                  buf.append('9');
                                  if (roundOff(buf)) {
                                      k++;
                                      buf.append('1');
                                  }
                                  return k + 1;
  //                                goto round_9_up;
                          }
                      }
                      buf.append(dig);
                      return k + 1;
                  }
                  if (j1 > 0) {
                      if (dig == '9') { /* possible if i == 1 */
  //                    round_9_up:
  //                        *s++ = '9';
  //                        goto roundoff;
                          buf.append('9');
                          if (roundOff(buf)) {
                              k++;
                              buf.append('1');
                          }
                          return k + 1;
                      }
                      buf.append((char)(dig + 1));
                      return k + 1;
                  }
                  buf.append(dig);
                  if (i == ilim)
                      break;
                  b = b.multiply(BigInteger.valueOf(10));
                  if (mlo == mhi)
                      mlo = mhi = mhi.multiply(BigInteger.valueOf(10));
                  else {
                      mlo = mlo.multiply(BigInteger.valueOf(10));
                      mhi = mhi.multiply(BigInteger.valueOf(10));
                  }
              }
          }
          else
              for(i = 1;; i++) {
  //                (char)(dig = quorem(b,S) + '0');
                  BigInteger[] divResult = b.divideAndRemainder(S);
                  b = divResult[1];
                  dig = (char)(divResult[0].intValue() + '0');
                  buf.append(dig);
                  if (i >= ilim)
                      break;
                  b = b.multiply(BigInteger.valueOf(10));
              }
  
          /* Round off last digit */
  
          b = b.shiftLeft(1);
          j = b.compareTo(S);
          if ((j > 0) || (j == 0 && (((dig & 1) == 1) || biasUp))) {
  //        roundoff:
  //            while(*--s == '9')
  //                if (s == buf) {
  //                    k++;
  //                    *s++ = '1';
  //                    goto ret;
  //                }
  //            ++*s++;
              if (roundOff(buf)) {
                  k++;
                  buf.append('1');
                  return k + 1;
              }
          }
          else {
              stripTrailingZeroes(buf);
  //            while(*--s == '0') ;
  //            s++;
          }
  //      ret:
  //        Bfree(S);
  //        if (mhi) {
  //            if (mlo && mlo != mhi)
  //                Bfree(mlo);
  //            Bfree(mhi);
  //        }
  //      ret1:
  //        Bfree(b);
  //        JS_ASSERT(s < buf + bufsize);
          return k + 1;
      }