现代C++如何创建constexpr数组的幂10?

zrfyljdw  于 2023-06-25  发布在  其他
关注(0)|答案(3)|浏览(251)
  1. #include <iostream>
  2. using namespace std;
  3. class FastFtoa {
  4. public:
  5. static inline constexpr double __inv_pow_10[] = {
  6. 1.0, // 0
  7. 0.1f, // 1
  8. 0.01, // 2
  9. 0.001, // 3
  10. 0.0001, // 4
  11. 0.00001, // 5
  12. 0.000001, // 6
  13. 0.0000001, // 7
  14. 0.00000001, // 8
  15. 0.000000001, // 9
  16. 0.0000000001, // 10
  17. 0.00000000001, // 11
  18. 0.000000000001, // 12
  19. 0.0000000000001, // 13
  20. 0.00000000000001, // 14
  21. 0.000000000000001, // 15
  22. 0.0000000000000001, // 16
  23. 0.00000000000000001, // 17
  24. 0.000000000000000001, // 18
  25. 0.0000000000000000001, // 19
  26. 0.00000000000000000001, // 20
  27. 0.000000000000000000001, // 21
  28. 0.0000000000000000000001, // 22
  29. 0.00000000000000000000001, // 23
  30. 0.000000000000000000000001, // 24
  31. 0.0000000000000000000000001, // 25
  32. 0.00000000000000000000000001, // 26
  33. 0.000000000000000000000000001, // 27
  34. 0.0000000000000000000000000001, // 28
  35. 0.00000000000000000000000000001, // 29
  36. 0.000000000000000000000000000001, // 30
  37. 0.0000000000000000000000000000001, // 31
  38. 0.00000000000000000000000000000001, // 32
  39. 0.000000000000000000000000000000001, // 33
  40. 0.0000000000000000000000000000000001, // 34
  41. 0.00000000000000000000000000000000001, // 35
  42. 0.000000000000000000000000000000000001, // 36
  43. 0.00000000000000000000000000000000000001, // 37
  44. 0.000000000000000000000000000000000000001 // 38
  45. };
  46. static inline constexpr double __pos_pow_10[] = {
  47. 1.0, // 0
  48. 10.0, // 1
  49. 100.0, // 2
  50. 1000.0, // 3
  51. 10000.0, // 4
  52. 100000.0, // 5
  53. 1000000.0, // 6
  54. 10000000.0, // 7
  55. 100000000.0, // 8
  56. 1000000000.0, // 9
  57. 10000000000.0, // 10
  58. 100000000000.0, // 11
  59. 1000000000000.0, // 12
  60. 10000000000000.0, // 13
  61. 100000000000000.0, // 14
  62. 1000000000000000.0, // 15
  63. 10000000000000000.0, // 16
  64. 100000000000000000.0, // 17
  65. 1000000000000000000.0, // 18
  66. 10000000000000000000.0, // 19
  67. 100000000000000000000.0, // 20
  68. 1000000000000000000000.0, // 21
  69. 10000000000000000000000.0, // 22
  70. 100000000000000000000000.0, // 23
  71. 1000000000000000000000000.0, // 24
  72. 10000000000000000000000000.0, // 25
  73. 100000000000000000000000000.0, // 26
  74. 1000000000000000000000000000.0, // 27
  75. 10000000000000000000000000000.0, // 28
  76. 100000000000000000000000000000.0, // 29
  77. 1000000000000000000000000000000.0, // 30
  78. 10000000000000000000000000000000.0, // 31
  79. 100000000000000000000000000000000.0, // 32
  80. 1000000000000000000000000000000000.0, // 33
  81. 10000000000000000000000000000000000.0, // 34
  82. 100000000000000000000000000000000000.0, // 35
  83. 1000000000000000000000000000000000000.0, // 36
  84. 10000000000000000000000000000000000000.0, // 37
  85. 100000000000000000000000000000000000000.0 // 38
  86. };
  87. };
  88. int main()
  89. {
  90. cout << FastFtoa::__inv_pow_10[37] << " " << FastFtoa::__pos_pow_10[37] << "\n";
  91. return 0;
  92. }

我需要创建10^x10^-xconstexpr数组,x范围-64..64 -38..38。它用于快速浮点到字符串转换。它还需要在一个静态类中(所有函数都是public static)。
可以像上面的代码一样手动创建它们,但看起来不太好。更不用说完整的float64范围是10^308,如果手动完成,这将是一个非常丑陋的代码。
在C++17/20中,什么是正确的方法?

1l5u6lss

1l5u6lss1#

  1. #include <algorithm>
  2. #include <array>
  3. #include <cmath>
  4. #include <iostream>
  5. #include <utility>
  6. template<typename T, T... ints>
  7. constexpr auto sequence1(std::integer_sequence<T, ints...>)
  8. {
  9. return std::array{std::pow(10L, ints)...};
  10. }
  11. template<typename T, T... ints>
  12. constexpr auto sequence2(std::integer_sequence<T, ints...>)
  13. {
  14. return std::array{(1/std::pow(10L, ints))...};
  15. }
  16. int main()
  17. {
  18. constexpr auto my_arr1 = sequence1(std::make_integer_sequence<size_t, 20>{});
  19. constexpr auto my_arr2 = sequence2(std::make_integer_sequence<size_t, 20>{});
  20. std::cout << my_arr1[5] << std::endl;
  21. std::cout << my_arr2[5] << std::endl;
  22. return 0;
  23. }
展开查看全部
cigdeys3

cigdeys32#

可以使用未命名的lambda初始化constexpr std::array,以减少命名空间混乱。inline对于静态constexprs是冗余的。

  1. #include <array>
  2. #include <iostream>
  3. class FastFtoa {
  4. public:
  5. static constexpr size_t N{39};
  6. static constexpr std::array<float, N> _pos_pow_10 = []() {
  7. std::array<float, N> x{1};
  8. for (size_t i = 1; i < N; i++)
  9. x[i] = 10*x[i-1];
  10. return x;
  11. }();
  12. static constexpr std::array<float, N> _inv_pow_10 = []() {
  13. std::array<float, N> x{1};
  14. for (size_t i = 1; i < N; i++)
  15. x[i] = .1f * x[i - 1];
  16. return x;
  17. }();
  18. };
  19. int main()
  20. {
  21. std::cout << FastFtoa::_pos_pow_10[0] << '\n';
  22. std::cout << FastFtoa::_pos_pow_10[38] << '\n';
  23. std::cout << FastFtoa::_inv_pow_10[0] << '\n';
  24. std::cout << FastFtoa::_inv_pow_10[38] << '\n';
  25. }

输出:

  1. 1
  2. 1e+38
  3. 1
  4. 1e-38
展开查看全部
wljmcqd8

wljmcqd83#

你可以利用std::array是constexpr的事实。只要您有可以在编译时完成的计算,您就可以用计算值填充该数组。
在该示例中:make_pow_10_map生成10的幂的Map。简单地在一个循环中将1.0f除以10.f,并在另一个循环中将1.0f乘以10.f。所有的值都存储在一个数组中(您可以轻松地对2个数组执行同样的操作)。
然后这个编译时数组被用在一个简单的查找函数中,该函数返回预先计算的值。

  1. #include <array>
  2. #include <iostream>
  3. #include <stdexcept>
  4. template<std::size_t N>
  5. static constexpr auto make_pow_10_map()
  6. {
  7. std::array<float, (2 * N)> values{};
  8. float value{ 1.0 };
  9. for (std::size_t n = (N-1); n > 0ul; --n)
  10. {
  11. values[n] = value;
  12. value /= 10.0f;
  13. }
  14. values[0] = value;
  15. value = 1.0;
  16. for (std::size_t n = (N-1); n < 2*N; ++n)
  17. {
  18. values[n] = value;
  19. value *= 10.0f;
  20. }
  21. return values;
  22. }
  23. float pow_10(int n)
  24. {
  25. constexpr std::size_t N{37ul};
  26. static constexpr auto powers_of_10 = make_pow_10_map<N>();
  27. int limit = N;
  28. if ((n < -limit) || (n > limit)) throw std::invalid_argument{"index out of range"};
  29. std::size_t index = (powers_of_10.size() / 2ul) + n - 1ul;
  30. return powers_of_10[index];
  31. }
  32. int main()
  33. {
  34. std::cout << pow_10(-3) << "\n";
  35. std::cout << pow_10(0) << "\n";
  36. std::cout << pow_10(6) << "\n";
  37. std::cout << pow_10(10) << "\n";
  38. std::cout << pow_10(11) << "\n";
  39. return 0;
  40. }
展开查看全部

相关问题