硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1141|回复: 1
收起左侧

[客户分享] 快速整型转字符实现

[复制链接]

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107884
QQ
发表于 2022-2-28 05:29:40 | 显示全部楼层 |阅读模式
https://jk-jeon.github.io/posts/2022/02/jeaiii-algorithm/

一般都用sprintf,itoa或者手动计算:

  1. char* itoa_naive(std::uint32_t n, char* buffer) {
  2.   char temp[10];
  3.   char* ptr = temp + sizeof(temp) - 1;
  4.   while (n >= 10) {
  5.     *ptr = char('0' + (n % 10));
  6.     n /= 10;
  7.     --ptr;
  8.   }
  9.   *ptr = char('0' + n);
  10.   auto length = temp + sizeof(temp) - ptr;
  11.   std::memcpy(buffer, ptr, length);
  12.   return buffer + length;
  13. }
复制代码


新实现:
  1. #include <cstdint>
  2. #include <cstring>
  3. #include <type_traits>

  4. static constexpr char radix_100_table[] = {
  5.     '0', '0', '0', '1', '0', '2', '0', '3', '0', '4',
  6.     '0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
  7.     '1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
  8.     '1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
  9.     '2', '0', '2', '1', '2', '2', '2', '3', '2', '4',
  10.     '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
  11.     '3', '0', '3', '1', '3', '2', '3', '3', '3', '4',
  12.     '3', '5', '3', '6', '3', '7', '3', '8', '3', '9',
  13.     '4', '0', '4', '1', '4', '2', '4', '3', '4', '4',
  14.     '4', '5', '4', '6', '4', '7', '4', '8', '4', '9',
  15.     '5', '0', '5', '1', '5', '2', '5', '3', '5', '4',
  16.     '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
  17.     '6', '0', '6', '1', '6', '2', '6', '3', '6', '4',
  18.     '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
  19.     '7', '0', '7', '1', '7', '2', '7', '3', '7', '4',
  20.     '7', '5', '7', '6', '7', '7', '7', '8', '7', '9',
  21.     '8', '0', '8', '1', '8', '2', '8', '3', '8', '4',
  22.     '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
  23.     '9', '0', '9', '1', '9', '2', '9', '3', '9', '4',
  24.     '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'
  25. };

  26. //      /\____________
  27. //     /  \______     \______
  28. //    /\   \     \     \     \
  29. //   0  1  /\    /\    /\    /\
  30. //        2  3  4  5  6  7  8  9
  31. char* itoa_better_y(std::uint32_t n, char* buffer) {
  32.   std::uint64_t prod;

  33.   auto get_next_two_digits = [&]() {
  34.     prod = std::uint32_t(prod) * std::uint64_t(100);
  35.     return int(prod >> 32);
  36.   };
  37.   auto print_1 = [&](int digit) {
  38.     buffer[0] = char(digit + '0');
  39.     buffer += 1;
  40.   };
  41.   auto print_2 = [&] (int two_digits) {
  42.     std::memcpy(buffer, radix_100_table + two_digits * 2, 2);
  43.     buffer += 2;
  44.   };
  45.   auto print = [&](std::uint64_t magic_number, int extra_shift, auto remaining_count) {
  46.     prod = n * magic_number;
  47.     prod >>= extra_shift;
  48.     auto two_digits = int(prod >> 32);

  49.     if (two_digits < 10) {
  50.       print_1(two_digits);
  51.       for (int i = 0; i < remaining_count; ++i) {
  52.         print_2(get_next_two_digits());
  53.       }
  54.     }
  55.     else {
  56.       print_2(two_digits);
  57.       for (int i = 0; i < remaining_count; ++i) {
  58.         print_2(get_next_two_digits());
  59.       }
  60.     }
  61.   };

  62.   if (n < 100) {
  63.     if (n < 10) {
  64.       // 1 digit.
  65.       print_1(n);
  66.     }
  67.     else {
  68.       // 2 digit.
  69.       print_2(n);
  70.     }
  71.   }
  72.   else {
  73.     if (n < 100'0000) {
  74.       if (n < 1'0000) {
  75.         // 3 or 4 digits.
  76.         // 42949673 = ceil(2^32 / 10^2)
  77.         print(42949673, 0, std::integral_constant<int, 1>{});
  78.       }
  79.       else {
  80.         // 5 or 6 digits.
  81.         // 429497 = ceil(2^32 / 10^4)
  82.         print(429497, 0, std::integral_constant<int, 2>{});
  83.       }
  84.     }
  85.     else {
  86.       if (n < 1'0000'0000) {
  87.         // 7 or 8 digits.
  88.         // 281474978 = ceil(2^48 / 10^6) + 1
  89.         print(281474978, 16, std::integral_constant<int, 3>{});
  90.       }
  91.       else {
  92.         if (n < 10'0000'0000) {
  93.           // 9 digits.
  94.           // 1441151882 = ceil(2^57 / 10^8) + 1
  95.           prod = n * std::uint64_t(1441151882);
  96.           prod >>= 25;
  97.           print_1(int(prod >> 32));
  98.           print_2(get_next_two_digits());
  99.           print_2(get_next_two_digits());
  100.           print_2(get_next_two_digits());
  101.           print_2(get_next_two_digits());
  102.         }
  103.         else {
  104.           // 10 digits.
  105.           // 1441151881 = ceil(2^57 / 10^8)
  106.           prod = n * std::uint64_t(1441151881);
  107.           prod >>= 25;
  108.           print_2(int(prod >> 32));
  109.           print_2(get_next_two_digits());
  110.           print_2(get_next_two_digits());
  111.           print_2(get_next_two_digits());
  112.           print_2(get_next_two_digits());
  113.         }
  114.       }
  115.     }
  116.   }
  117.   return buffer;
  118. }

  119. #include <iostream>

  120. int main() {
  121.     char buffer[11];
  122.     *itoa_better_y(1, buffer) = '\0';
  123.     std::cout << buffer << "\n";
  124.     *itoa_better_y(12, buffer) = '\0';
  125.     std::cout << buffer << "\n";
  126.     *itoa_better_y(123, buffer) = '\0';
  127.     std::cout << buffer << "\n";
  128.     *itoa_better_y(1234, buffer) = '\0';
  129.     std::cout << buffer << "\n";
  130.     *itoa_better_y(12345, buffer) = '\0';
  131.     std::cout << buffer << "\n";
  132.     *itoa_better_y(123456, buffer) = '\0';
  133.     std::cout << buffer << "\n";
  134.     *itoa_better_y(1234567, buffer) = '\0';
  135.     std::cout << buffer << "\n";
  136.     *itoa_better_y(12345678, buffer) = '\0';
  137.     std::cout << buffer << "\n";
  138.     *itoa_better_y(123456789, buffer) = '\0';
  139.     std::cout << buffer << "\n";
  140.     *itoa_better_y(1234567890, buffer) = '\0';
  141.     std::cout << buffer << "\n";
  142. }
复制代码




回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107884
QQ
 楼主| 发表于 2022-2-28 05:31:54 | 显示全部楼层
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-6-17 10:41 , Processed in 0.258830 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表