I want to stringify a fraction of unsigned integers in C++ with variable precision. So 1/3
would be printed as 0.33
using a precision
of 2
. I know that float
and std::ostream::precision
could be used for a quick and dirty solution:
std::string stringifyFraction(unsigned numerator,
unsigned denominator,
unsigned precision)
{
std::stringstream output;
output.precision(precision);
output << static_cast<float>(numerator) / denominator;
return output.str();
}
However, this is not good enough because float
has limited precision and can't actually represent decimal numbers accurately. What other options do I have? Even a double
would fail if I wanted 100 digits or so, or in case of a recurring fraction.
It's always possible to just perform long division to stringify digit-by-digit. Note that the result consists of an integral part and a fractional part. We can get the integral part by simply dividing using the /
operator and calling std::to_string
. For the rest, we need the following function:
#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;
}
You could easily extend this to work with other bases as well, by just making base
a template parameter, but then you couldn't just use std::to_string
anymore.