std::to_chars() 最小浮点缓冲区大小

owa*_*der 10 c++ formatting number-formatting c++17

给定一个通用整数类型IntType,很容易确定以std::to_chars10 为基数的数字操作所需的缓冲区类型:

std::array<char, std::numeric_limits<IntType>::digits10 + 1 + std::is_signed<IntType>::value> buf;
Run Code Online (Sandbox Code Playgroud)

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

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

owa*_*der 10

请注意,所需的最小缓冲区根据所需的浮点格式而有所不同。假设不想输出比浮点类型包含的精度更高的精度,则使用max_digits10and始终足以确定以 10 为基数输出所需的最小字符数。max_exponent10

这个问题也不仅限于to_chars。该printf系列中的 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;
    
    Run Code Online (Sandbox Code Playgroud)

    该函数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;
    
    Run Code Online (Sandbox Code Playgroud)

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

    添加 2 个字符可容纳输出中可能的符号和小数点。

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

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

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