如何输出浮点数
  • 板块学术版
  • 楼主normalpcer
  • 当前回复1
  • 已保存回复1
  • 发布时间2025/1/19 21:27
  • 上次更新2025/1/20 09:41:01
查看原帖
如何输出浮点数
745184
normalpcer楼主2025/1/19 21:27

C++ 中,大多数能够输出浮点数的函数似乎都有这样一个特性:对于任意一个能够被 double 类型精确表示的整数值 xx,若 x2Nx \cdot 2^NNN 为整数)不会超过 double 类型的上界,那么这个值可以被完全精确地转换为十进制形式输出。

例如:

#include <cmath>
#include <cstdio>
#include <iostream>
#include <iomanip>
#include <format>

int main() {
    double x = 3.0 * std::pow(2, 128);
    std::printf("printf %.0lf\n", x);
    std::cout << std::fixed << std::setprecision(0) << "cout " << x << std::endl;
    std::cout << std::format("format {:.0f}", x) << std::endl;
    return 0;
}

输出(GCC 和 Clang 编译器均为此结果):

printf 1020847100762815390390123822295304634368
cout 1020847100762815390390123822295304634368
format 1020847100762815390390123822295304634368

这与 Python 的高精度整数计算结果完全一致。

而简单的手写输出函数无法支持这样的特性。

template <typename T, typename std::enable_if<is_floating_point_or_float128<T>::value>::type* = nullptr>
Printer &write(T x) {
    if (std::isnan(x))  return write("nan");
    static char st[std::numeric_limits<T>::max_exponent10+1];
    char *top = st;
    if (x < 0)  x = -x, put('-');
    if (std::isinf(x))  return write("Infinity");
    auto y = std::floor(x);
    while (y >= 1) {
        auto cur = std::fmod(y, 10);
        y = (y - cur) / 10;
        *top++ = (int)(cur) ^ 48;
    }
    if (top == st)  put('0');
    while (top != st)  put(*--top);
    x -= std::floor(x);
    put('.');
    for (auto i = 0; i < 6; i++) {
        x = x * 10;
        auto cur = std::floor(x);
        x -= cur;
        put((int)cur ^ 48);
    }
    return *this;
}
// ...
io << "IO: " << x << "\n";

输出:

1020847100762815628066424846468008666808.000000

如何以十进制输出一个浮点数,使得能够支持这样的特性?换句话说,标准库的浮点数输出是如何实现的?

2025/1/19 21:27
加载中...