Print a max of 4 decimals

976 Views Asked by At

I'm trying to print a max of 4 digits after the decimal point in C++ (Using streams). So if the number does not need 4 digits after the decimal I want it to use only the number of decimals it actually needs.

Examples:

1.12345    -> 1.1234
1.0        -> 1
1.12       -> 1.12
1.12345789 -> 1.1234
123.123    -> 123.123
123.123456 -> 123.1234

I tried std::setprecision(4) but that sets the number of significant digits and fails in the test case:

123.123456 gives 123.1

I also tried giving std::fixed along with std::setprecision(4) but that gives a fixed number of digits after decimal even if not needed:

1.0 gives 1.0000

It seems like std::defaultfloat is the one I need and not fixed nor exponential. But it does not seem to be printing the number of digits after the decimal appropriately and only has an option for significant digits.

2

There are 2 best solutions below

0
On BEST ANSWER

We can do this using a std::stringstream and a std::string. We pass the double to the stream formatting it like we would if we are sending it to cout. Then we examine the string we get from the stream to see if there are trailing zeros. If there are we get rid of them. Once we do that we check to see if we are left with just a decimal point, if we are then we get rid of that as well. You could use something like this:

int main()
{
    double values[] = { 1.12345, 1.0, 1.12, 1.12345789, 123.123, 123.123456, 123456789, 123.001 };
    std::vector<std::string> converted;
    for (auto e : values)
    {
        std::stringstream ss;
        ss << std::fixed << std::setprecision(4) << e;
        std::string value(ss.str());
        if (value.find(".") != std::string::npos)
        {
            // erase trailing zeros
            while (value.back() == '0')
                value.erase(value.end() - 1);
            // if we are left with a . at the end then get rid of it
            if (value.back() == '.')
                value.erase(value.end() - 1);
            converted.push_back(value);
        }
        else
            converted.push_back(value);
    }
    for (const auto& e : converted)
        std::cout << e << "\n";
}

Which when made into a running example gives

1.1235
1
1.12
1.1235
123.123
123.1235
123456789
123.001
0
On

Using the answer from here along with custom logic to remove the zeros and the point:

#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>

std::string remove_zeros(std::string numberstring)
{
    auto it = numberstring.end() - 1;
    while(*it == '0') {
        numberstring.erase(it);
        it = numberstring.end() - 1;
    }
    if(*it == '.') numberstring.erase(it);
    return numberstring;
}

std::string convert(float number)
{
    std::stringstream ss{};
    ss << std::setprecision(4) << std::fixed << std::showpoint << number;
    std::string numberstring{ss.str()};
    return remove_zeros(numberstring);
}

int main()
{
    const float values[]{1.12345, 1.0, 1.12, 1.12345789, 147323.123, 123.123456};
    for(auto i : values)
        std::cout << convert(i) << '\n';
}

produces:

1.1235
1
1.12
1.1235
147323.125
123.1235