JKJ_FORCEINLINE static void print_9_digits()

in include/ylt/standalone/iguana/detail/dragonbox_to_chars.h [95:287]


JKJ_FORCEINLINE static void print_9_digits(std::uint32_t s32, int &exponent,
                                           char *&buffer) noexcept {
  // -- IEEE-754 binary32
  // Since we do not cut trailing zeros in advance, s32 must be of 6~9 digits
  // unless the original input was subnormal.
  // In particular, when it is of 9 digits it shouldn't have any trailing zeros.
  // -- IEEE-754 binary64
  // In this case, s32 must be of 7~9 digits unless the input is subnormal,
  // and it shouldn't have any trailing zeros if it is of 9 digits.
  if (s32 >= 1'0000'0000) {
    // 9 digits.
    // 1441151882 = ceil(2^57 / 1'0000'0000) + 1
    auto prod = s32 * std::uint64_t(1441151882);
    prod >>= 25;
    std::memcpy(buffer, radix_100_head_table + std::uint32_t(prod >> 32) * 2,
                2);

    prod = std::uint32_t(prod) * std::uint64_t(100);
    std::memcpy(buffer + 2, radix_100_table + std::uint32_t(prod >> 32) * 2, 2);
    prod = std::uint32_t(prod) * std::uint64_t(100);
    std::memcpy(buffer + 4, radix_100_table + std::uint32_t(prod >> 32) * 2, 2);
    prod = std::uint32_t(prod) * std::uint64_t(100);
    std::memcpy(buffer + 6, radix_100_table + std::uint32_t(prod >> 32) * 2, 2);
    prod = std::uint32_t(prod) * std::uint64_t(100);
    std::memcpy(buffer + 8, radix_100_table + std::uint32_t(prod >> 32) * 2, 2);

    exponent += 8;
    buffer += 10;
  }
  else if (s32 >= 100'0000) {
    // 7 or 8 digits.
    // 281474978 = ceil(2^48 / 100'0000) + 1
    auto prod = s32 * std::uint64_t(281474978);
    prod >>= 16;
    auto two_digits = std::uint32_t(prod >> 32);
    // If s32 is of 8 digits, increase the exponent by 7.
    // Otherwise, increase it by 6.
    exponent += (6 + unsigned(two_digits >= 10));

    // Write the first digit and the decimal point.
    std::memcpy(buffer, radix_100_head_table + two_digits * 2, 2);
    // This third character may be overwritten later but we don't care.
    buffer[2] = radix_100_table[two_digits * 2 + 1];

    // Remaining 6 digits are all zero?
    if (std::uint32_t(prod) <=
        std::uint32_t((std::uint64_t(1) << 32) / 100'0000)) {
      // The number of characters actually written is:
      //   1, if only the first digit is nonzero, which means that either s32 is
      //   of 7 digits or it is of 8 digits but the second digit is zero, or 3,
      //   otherwise.
      // Note that buffer[2] is never zero if s32 is of 7 digits, because the
      // input is never zero.
      buffer +=
          (1 + (unsigned(two_digits >= 10) & unsigned(buffer[2] > '0')) * 2);
    }
    else {
      // At least one of the remaining 6 digits are nonzero.
      // After this adjustment, now the first destination becomes buffer + 2.
      buffer += unsigned(two_digits >= 10);

      // Obtain the next two digits.
      prod = std::uint32_t(prod) * std::uint64_t(100);
      two_digits = std::uint32_t(prod >> 32);
      std::memcpy(buffer + 2, radix_100_table + two_digits * 2, 2);

      // Remaining 4 digits are all zero?
      if (std::uint32_t(prod) <=
          std::uint32_t((std::uint64_t(1) << 32) / 1'0000)) {
        buffer += (3 + unsigned(buffer[3] > '0'));
      }
      else {
        // At least one of the remaining 4 digits are nonzero.

        // Obtain the next two digits.
        prod = std::uint32_t(prod) * std::uint64_t(100);
        two_digits = std::uint32_t(prod >> 32);
        std::memcpy(buffer + 4, radix_100_table + two_digits * 2, 2);

        // Remaining 2 digits are all zero?
        if (std::uint32_t(prod) <=
            std::uint32_t((std::uint64_t(1) << 32) / 100)) {
          buffer += (5 + unsigned(buffer[5] > '0'));
        }
        else {
          // Obtain the last two digits.
          prod = std::uint32_t(prod) * std::uint64_t(100);
          two_digits = std::uint32_t(prod >> 32);
          std::memcpy(buffer + 6, radix_100_table + two_digits * 2, 2);

          buffer += (7 + unsigned(buffer[7] > '0'));
        }
      }
    }
  }
  else if (s32 >= 1'0000) {
    // 5 or 6 digits.
    // 429497 = ceil(2^32 / 1'0000)
    auto prod = s32 * std::uint64_t(429497);
    auto two_digits = std::uint32_t(prod >> 32);

    // If s32 is of 6 digits, increase the exponent by 5.
    // Otherwise, increase it by 4.
    exponent += (4 + unsigned(two_digits >= 10));

    // Write the first digit and the decimal point.
    std::memcpy(buffer, radix_100_head_table + two_digits * 2, 2);
    // This third character may be overwritten later but we don't care.
    buffer[2] = radix_100_table[two_digits * 2 + 1];

    // Remaining 4 digits are all zero?
    if (std::uint32_t(prod) <=
        std::uint32_t((std::uint64_t(1) << 32) / 1'0000)) {
      // The number of characters actually written is 1 or 3, similarly to the
      // case of 7 or 8 digits.
      buffer +=
          (1 + (unsigned(two_digits >= 10) & unsigned(buffer[2] > '0')) * 2);
    }
    else {
      // At least one of the remaining 4 digits are nonzero.
      // After this adjustment, now the first destination becomes buffer + 2.
      buffer += unsigned(two_digits >= 10);

      // Obtain the next two digits.
      prod = std::uint32_t(prod) * std::uint64_t(100);
      two_digits = std::uint32_t(prod >> 32);
      std::memcpy(buffer + 2, radix_100_table + two_digits * 2, 2);

      // Remaining 2 digits are all zero?
      if (std::uint32_t(prod) <=
          std::uint32_t((std::uint64_t(1) << 32) / 100)) {
        buffer += (3 + unsigned(buffer[3] > '0'));
      }
      else {
        // Obtain the last two digits.
        prod = std::uint32_t(prod) * std::uint64_t(100);
        two_digits = std::uint32_t(prod >> 32);
        std::memcpy(buffer + 4, radix_100_table + two_digits * 2, 2);

        buffer += (5 + unsigned(buffer[5] > '0'));
      }
    }
  }
  else if (s32 >= 100) {
    // 3 or 4 digits.
    // 42949673 = ceil(2^32 / 100)
    auto prod = s32 * std::uint64_t(42949673);
    auto two_digits = std::uint32_t(prod >> 32);

    // If s32 is of 4 digits, increase the exponent by 3.
    // Otherwise, increase it by 2.
    exponent += (2 + int(two_digits >= 10));

    // Write the first digit and the decimal point.
    std::memcpy(buffer, radix_100_head_table + two_digits * 2, 2);
    // This third character may be overwritten later but we don't care.
    buffer[2] = radix_100_table[two_digits * 2 + 1];

    // Remaining 2 digits are all zero?
    if (std::uint32_t(prod) <= std::uint32_t((std::uint64_t(1) << 32) / 100)) {
      // The number of characters actually written is 1 or 3, similarly to the
      // case of 7 or 8 digits.
      buffer +=
          (1 + (unsigned(two_digits >= 10) & unsigned(buffer[2] > '0')) * 2);
    }
    else {
      // At least one of the remaining 2 digits are nonzero.
      // After this adjustment, now the first destination becomes buffer + 2.
      buffer += unsigned(two_digits >= 10);

      // Obtain the last two digits.
      prod = std::uint32_t(prod) * std::uint64_t(100);
      two_digits = std::uint32_t(prod >> 32);
      std::memcpy(buffer + 2, radix_100_table + two_digits * 2, 2);

      buffer += (3 + unsigned(buffer[3] > '0'));
    }
  }
  else {
    // 1 or 2 digits.
    // If s32 is of 2 digits, increase the exponent by 1.
    exponent += int(s32 >= 10);

    // Write the first digit and the decimal point.
    std::memcpy(buffer, radix_100_head_table + s32 * 2, 2);
    // This third character may be overwritten later but we don't care.
    buffer[2] = radix_100_table[s32 * 2 + 1];

    // The number of characters actually written is 1 or 3, similarly to the
    // case of 7 or 8 digits.
    buffer += (1 + (unsigned(s32 >= 10) & unsigned(buffer[2] > '0')) * 2);
  }
}