我怎样才能在 C++ 中用 N 个小数字符串化一个分数

How can I stringify a fraction with N decimals in C++

我想在 C++ 中以可变精度对一部分无符号整数进行字符串化。因此 1/3 将使用 2precision 打印为 0.33。我知道 floatstd::ostream::precision 可用于快速而肮脏的解决方案:

std::string stringifyFraction(unsigned numerator,
                              unsigned denominator,
                              unsigned precision)
{
    std::stringstream output;
    output.precision(precision);
    output << static_cast<float>(numerator) / denominator;
    return output.str();
}

然而,这还不够好,因为 float 精度有限,实际上无法准确表示十进制数。我还有哪些其他选择?如果我想要 100 位左右的数字,或者在循环分数的情况下,即使 double 也会失败。

总是可以只执行长除法来字符串化digit-by-digit。请注意,结果由整数部分和小数部分组成。我们可以通过简单地使用 / 运算符进行除法并调用 std::to_string 来获得整数部分。对于其余部分,我们需要以下功能:

#include <string>

std::string stringifyFraction(const unsigned num,
                              const unsigned den,
                              const unsigned precision)
{
    constexpr unsigned base = 10;

    // prevent division by zero if necessary
    if (den == 0) {
        return "inf";
    }

    // integral part can be computed using regular division
    std::string result = std::to_string(num / den);
    
    // perform first step of long division
    // also cancel early if there is no fractional part
    unsigned tmp = num % den;
    if (tmp == 0 || precision == 0) {
        return result;
    }

    // reserve characters to avoid unnecessary re-allocation
    result.reserve(result.size() + precision + 1);

    // fractional part can be computed using long divison
    result += '.';
    for (size_t i = 0; i < precision; ++i) {
        tmp *= base;
        char nextDigit = '0' + static_cast<char>(tmp / den);
        result.push_back(nextDigit);
        tmp %= den;
    }

    return result;
}

您可以轻松地将其扩展为与其他基础一起使用,只需将 base 设为模板参数即可,但您不能再只使用 std::to_string