-2

I try to multiply an integer by a double but I obtain a wrong result. In my example the result of v * decimals is 11.9999999999... instead of 12 although when I print it using cout it shows 12 (I see the value using gdb), then static_cast set 11 in uint64_t a. Why does this happen? What is the correct way to multiply an integer and a double?

#include <iostream>

int main(int argc, char *argv[])
{
    const uint64_t decimals = 100000000;
    double v = 0.00000012;
    uint64_t a = 0;

    std::cout << "Initial value=" << v << std::endl;
    v = v * decimals;
    std::cout << "v * decimals=" << v << std::endl;
    a = static_cast<uint64_t>(v);
    std::cout << "a=" << a << std::endl;

    return 0;
}

output:

Initial value=1.2e-07
v * decimals=12
a=11
Norv
  • 13
  • 1
  • 4
  • Short answer: due to rounding, `v * decimals` most likely has a value like `11.9999999`. When printing it to stdout you get the value rounded (to as many places as are being printed), but when casting to an integer it's always truncated. – Nate Eldredge Feb 29 '20 at 17:53
  • 1
    Take some time to read [What Every Computer Scientist Should Know About Floating-Point Arithmetic](https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) – Jesper Juhl Feb 29 '20 at 17:55

1 Answers1

3

v * decimals is 11.9999999999... instead of 12 although when I print it using cout it shows 12

Why does this happen?

Because std::ostream rounds the output. The precision of the rounding can be controlled with std::setprecision io-manipulator.

then static_cast set 11 in uint64_t a.

Why does this happen?

Because converting floating point to integer discards everything on the right side of decimal point. 11.XXX becomes 11 regardless of XXX.

What is the correct way to multiply an integer and a double?

You've shown a correct way.

What is not correct is the expectation that the result of multiplication contains no error. And floor operation (which occurs upon conversion to integer) can magnify the error. If you want the integer to have the value 12, then round the result of multiplication first.

Community
  • 1
  • 1
eerorika
  • 232,697
  • 12
  • 197
  • 326
  • You still haven't answered the question. Why `v * decimals` should be 11.99999...? – Omid.N Feb 29 '20 at 17:59
  • 2
    @omid `v` is not `0.00000012` it's probably actually `0.00000011999999`, in many cases decimal literals aren't exactly representable in binary floating point numbers – Alan Birtles Feb 29 '20 at 18:06
  • Yes, I know but this is not the question... the question is Why `v * decimal` is `11.9999999` instead of `12`. I did not realize that this has already been asked here => https://stackoverflow.com/questions/588004/is-floating-point-math-broken?page=1&tab=votes#tab-top – Norv Mar 01 '20 at 09:25