【问题标题】:How can I stringify a fraction with N decimals in C++如何在 C++ 中用 N 个小数对分数进行字符串化
【发布时间】:2020-08-20 19:02:53
【问题描述】:

我想在 C++ 中以可变精度对一小部分无符号整数进行字符串化。所以1/3 将使用precision2 打印为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 也会失败。

【问题讨论】:

  • 您的问题似乎不是转换为字符串,而是您想要一种表示有理数而又不损失精度的方法。问题的标题可能是您的最终目标,但这不是您的实际问题。
  • @FrançoisAndrieux 我不确定你是如何得出这个结论的。我已经有了一个无损表示:分子和分母。我发布此问答的原因是因为我经常遇到这个问题,例如将uint8_t RGB 值打印到[0, 1] 十进制范围内的文件中。或以字节为单位打印文件大小为x.yyy MB

标签: c++ string math c++17 base


【解决方案1】:

总是可以只执行长除法以逐位字符串化。请注意,结果由整数部分和小数部分组成。我们可以通过简单地使用/ 运算符和调用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

【讨论】:

  • OP 可能还想显示重复的小数。喜欢9/11 = 0.(81)。这将是对这个已经很好的答案的简单补充
猜你喜欢
  • 1970-01-01
  • 2014-08-05
  • 1970-01-01
  • 2016-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-10
相关资源
最近更新 更多