【问题标题】:std::to_chars() minimal floating point buffer sizestd::to_chars() 最小浮点缓冲区大小
【发布时间】:2021-09-29 00:28:00
【问题描述】:

给定一个通用整数类型IntType,很容易确定基数为10 的std::to_chars 运算所需的缓冲区类型:

std::array<char, std::numeric_limits<IntType>::digits10 + 1 + std::is_signed<IntType>::value> buf;

由于std::to_chars 不以 NUL 结尾,并且只添加数字(以及可能的前面 '-',如果有符号),这应该适用于所有内置整数类型。 + 1 是必需的,因为 digits10 for integral types 返回以 10 为底的对数的底数,而不是上限。

这就引出了一个问题:使用每个std::chars_format 值,给定一个通用FloatType 进行无损失转换(写入所有十进制数字)的浮点std::to_chars 调用的最小缓冲区大小是多少?

【问题讨论】:

  • @Jarod42 - 不幸的是,这不适用于定点表示法,也不包括由于用科学计数法编写的指数而可以添加的字符数。
  • 那么可能是std::numeric_limits::max_digits10+10。不会错过一些额外的字节。
  • 您只需要足够的位数来保证类型的精度。 to_char 不能比传递给它的类型更精确。
  • @NicolBolas - 因为具有正指数的固定符号数字没有无关紧要或不相关的数字,这与您使用负指数的示例不同。 max_digits10 使用像 1e38 这样的大值的定点符号将失败。

标签: c++ formatting c++17 number-formatting


【解决方案1】:

请注意,所需的最小缓冲区因所需的浮点格式而异。假设不想输出比浮点类型包含的精度更高的精度,使用 max_digits10max_exponent10 始终足以确定以 10 为底的输出所需的最小字符数。

这个问题也不仅仅局限于to_charsprintf 系列中的 C 标准库函数将具有相同的行为,因此这在 C 中的重要性与在 C++ 中相同。

  • std::chars_format::scientific%e (printf specifier)

    template<typename T>
    constexpr int log10ceil(T num) {
        return num < 10? 1: 1 + log10ceil(num / 10);
    }
    
    std::array<char, 4 + 
                     std::numeric_limits<FloatType>::max_digits10 + 
                     std::max(2, log10ceil(std::numeric_limits<FloatType>::max_exponent10))
              > buf;
    

    log10ceil 函数允许 constexpr 评估最大指数中的位数。根据标准,指数中必须至少有 2 位数字,因此针对最小指数宽度进行测试。写入时使用的精度不得大于max_digits10 - 1。使用这种精确的精度将无损转换为字符串表示形式。

    添加的 4 个字符包含输出中可能的符号、小数点和 "e+""e-"

  • std::chars_format::fixed%f (printf specifier)

    std::array<char, 2 + 
                     std::numeric_limits<FloatType>::max_exponent10 +
                     std::numeric_limits<FloatType>::max_digits10
              > buf;
    

    同样,使用的精度不得大于max_digits10 - 1。使用这种精确的精度将无损转换为字符串表示形式。

    添加 2 个字符以适应输出中可能的符号和小数点。

  • std::chars_format::general%g (printf specifier):

    对于general 情况,最小缓冲区始终与scientific 情况相同。 但是,使用的精度必须不大于 max_digits10 才能无损转换为字符串表示,而不是如上所述的减一。

请注意,在所有这些示例中,缓冲区正好是最大字符串表示的大小。如果需要 NUL 终止符或其他内容,则必须相应增加大小。

【讨论】:

  • 我们能否预先确定给定值、格式和精度所需的缓冲区大小?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-22
相关资源
最近更新 更多