std::round(4.1)
can give 4.000000000001
or 3.99999999999
. In later case, casting to int gives 3 right?
That's true. 4.1
can be seen as 4.0
(which has exact representation in floating point as an integer it is) plus 0.1
, which can be seen as 1/10
(it's exactly 1/10
, indeed) And the problem you will have is if you try to round a number close to that to one decimal point after the decimal mark (rounding to an integer multiple of 0.1
or 0.01
or 0.001
, etc.)
If you are using decimal floating point (which normally C compilers don't) then you are lucky, as 0.1
is 10&^(-1)
which again has an exact representation in the machine. But as a binary floating point number, it has an infinite representation in binary as 0.000110011001100110011001100...b
and it depends where you cut the number you will get some value or another, but you will never get the exact value as a decimal number (with a finite number of digits)
But the way round()
works is not that... if first adds 0.5
(which is exactly representable as a binary floating point number) to the number (this results in an exact operation, no rounding error emerges from it), and then cuts the integer part (which is also an exact operation), meaning that you are getting always an exact integer result (which is perfectly representable as an exact floating point, if the original number was). The rounding is equivalent to this set of operations:
(int)(4.1 + 0.5);
so you will get the integer part of 4.6
after addding the 0.5
part (or something like 4.60000000000000003
, 4.59999999999999998
, anyway both will be truncated to 4.0
, which is also exactly representable in binary floating point format) so you will never get a wrong answer for the rounding to integer case... you can get a wrong response in case you get something close to 4.5
(which can round to 4.0
instead of the correct rounding to 5.0
, but .5
happens to be exactly 0.1b
in binary... and so it's not affected --
Beware although that rounding to multiples of a negative power of ten (0.1
, 0.01
, ...) is not warranted, as none of those numbers is representable exactly in binary floating point. All of them have an infinite representation as binary numbers, and due to the cutting at some point, they can be represented as a tiny number above or below (depending on which is close) and the rounding will not work.