25

Currently, I can round a double to an output stream using:

output.setf(std::ios::fixed,std::ios::floatfield);
output.precision(3);

But I'm given a double and I need to make the conversion before I insert it to a vector. So for instance, if the number -0.00078 appears then it equals to 0.000 and I won't need to save it. On the other hand, 1.0009 will become 1.001 (same as the precision function handles it).

How can I convert doubles like that in C++?

Melebius
  • 5,590
  • 3
  • 34
  • 46
Tom
  • 8,775
  • 24
  • 84
  • 144

4 Answers4

42

A common trick is to do it with maths:

value = round( value * 1000.0 ) / 1000.0;

Where round will handle negative and positive values correctly... Something like this (untested):

inline double round( double val )
{
    if( val < 0 ) return ceil(val - 0.5);
    return floor(val + 0.5);
}

You'll still want to set the decimal places to 3 during output, due to floating point precision problems.

paddy
  • 55,641
  • 6
  • 55
  • 99
  • 4
    There are already [a bunch of standard-library functions for rounding](http://en.cppreference.com/w/c/numeric/math/round), no? – Oliver Charlesworth Jan 16 '13 at 23:36
  • 1
    @OliverCharlesworth the std::round functions only round to the nearest integer. For decimal point, you will need to do the trick that paddy suggested. – Yun Sep 13 '16 at 17:52
  • 7
    @yun No, he means you don't need to define your own `round` function like I did there because it already exists. – paddy Sep 14 '16 at 02:44
  • `floor(val + 0.5)` fails many cases when `val + 0.5` is inexact. `round( value * 1000.0 ) / 1000.0` has similar troubles - for values near half-way. (when `value * 1000.0` is near `xxxxx.5`. – chux - Reinstate Monica Jul 04 '21 at 11:26
10

I know this is a very old post but I was looking for a solution to the same problem. However, I did not want to create a special function for it so I came up with the following:

#include <sstream>
#include <iomanip>
...
...
...
double val = 3.14159;
stringstream tmp;
tmp << setprecision(3) << fixed << val;
double new_val = stod(tmp.str());   // new_val = 3.143
tmp.str(string());                  // clear tmp for future use

Not sure if this is the best way to do it but it worked for me!

classyGrrrl
  • 101
  • 1
  • 2
  • This is an easy way to get the rounding done without having to write math expressions explicitly. However, wouldn't the two conversions between string and float make this less efficient that using a math formula? Of course, the performance overhead should be barely visible if the rounding is to be done for just a few numbers, not for tons of them. – so2 Feb 04 '21 at 18:14
9

Other answers here have given you a technique. But it's important to mention that not all values can be exactly represented in floating-point. 1.001 is a good example; the nearest possible value is 1.00099999999999988987.

So if your aim is to get strictly 3 decimal places, then the answer is: that's not possible.

Oliver Charlesworth
  • 260,367
  • 30
  • 546
  • 667
  • Well, technically you can. You round the number to a whole and output that with no decimal places, then you multiply the original by 1000 and `fmod` by 1000 and output that as an integer with leading zeros. Oh yeah, and output the decimal point. – paddy Jan 16 '13 at 23:33
  • @paddy: Yes, that's true. If you're prepared to work with `1000*x` at all points through your calculations, then you absolutely can. (Perhaps you should put this in your answer.) – Oliver Charlesworth Jan 16 '13 at 23:35
5

You can multiply it by 1000 and then round (or truncate) it; this will give you a value 1000 times the 3-decimal place value. Note that, if you divide it by 1000 to get the 'rounded' value, you may end up w/ more than 3 decimal places (due to round off error).

Scott Hunter
  • 46,905
  • 10
  • 55
  • 92
  • I think the round off error due to /1000 is important to take into account, indeed. – mfnx Oct 17 '20 at 17:41