views:

1472

answers:

3

How do I write a function that formats a string with decimals digits, without trailing 0's or unnecessary 9's? Given that decimals is 2, here's what I expect:

0.999 -> 1.0
0.99 -> 0.99
1.01 -> 1.01
1.001 -> 1.0
123 -> 123.0
0 -> 0.0
0.1 -> 0.1

(negatives as you'd expect)

Here's what I have so far, but it's pretty ugly code. Is there a nicer way to do this?

string toStrMaxDecimals(double value, uint decimals) {
    value *= pow(10, decimals);
    value = round(value);
    value *= pow(0.1, decimals);
    string temp = boost::lexical_cast<string>(value); 
    size_t dot = temp.find('.');
    if (dot != string::npos) {
     if (temp.size() > dot + decimals + 1)
      temp.erase(dot + decimals + 1);
     if (*temp.rbegin() == '0')
      temp.erase(temp.find_last_not_of("0") + 1);
     if (*temp.rbegin() == '.')
      temp.append("0");
    } else {
     temp.append(".0");
    }
    return temp;
}
A: 
Matthias Wandel
thanks for the answer, but I'd like to produce the output I've got, which I think is pretty readable. (A lot better than the user types in 0.7 and gets 0.7000000000003 or something.) After browsing SO, I found find_last_not_of, which was pretty useful, so I was wondering if anyone had any other string tricks.
Neil G
(also converting to int kind of defeats the purpose of using double precision numbers)
Neil G
+4  A: 
std::string toStrMaxDecimals(double value, int decimals)
{
    std::ostringstream ss;
    ss << std::fixed << std::setprecision(decimals) << value;
    std::string s = ss.str();
    if(decimals > 0 && s[s.find_last_not_of('0')] == '.') {
        s.erase(s.size() - decimals + 1);
    }
    return s;
}
Don
this is excellent! If no one can do better by tomorrow, I'll accept it. I knew it was possible to do this better. Thanks.
Neil G
I tested this, and it was close: 0.1 gives 0.10. So, I merged your solution with mine-- using ostringstream to do the the rounding and stringifying, and my code to clean up the result. Thanks again.
Neil G
+2  A: 

sprintf is going to be far easier, more readable and more performance than C++ streams. You don't need to do any rounding or trimming yourself. Sprintf has flags for that. You probably want something like

sprintf(targetBuffer, "%.2g", floatingPointValue);

Sprintf does the rounding in Java, and I'm pretty sure it will in C++ as well.

EDIT:

Sorry, the example code I wrote is for your example. For your original question, change the %.2g to %.6g

EDIT:

Changed f to g to suppress trailing zeroes.

Jherico
close, thanks, but it likes 2 is digits of precision and not number of decimals.0.999 -> 10.99 -> 0.991.01 -> 11.001 -> 1123 -> 1.2e+020 -> 00.1 -> 0.1
Neil G