2

Possible Duplicate:
Why does this double to int conversion not work?

Convert double to int lose 1 in c++

#include <iostream>
#include <cmath>
using namespace std;

void main() {

    double num = 1234.34;
    int numInt = num;
    double numAfterPoint = num - numInt; // 0.34

    int counter = 1;
    double numFloatPower = numAfterPoint;

    while (true) {
        numFloatPower = numAfterPoint * pow(10.0, counter);
        cout << numFloatPower << " > " << (int)numFloatPower << " ";
        system("pause");
        counter++;
    }

}

The current result :

3.4 > 3 Press any key to continue . . .
34 > 33 Press any key to continue . . .
340 > 339 Press any key to continue . . .
3400 > 3399 Press any key to continue . . .

Result Should Be :

3.4 > 3 Press any key to continue . . .
34 > 34 Press any key to continue . . .
340 > 340 Press any key to continue . . .
3400 > 3400 Press any key to continue . . .

etc ...

Community
  • 1
  • 1
faressoft
  • 19,053
  • 44
  • 104
  • 146

5 Answers5

5

The cast-to-int operation (int)doubleValue performs truncation, which means if the number is represented internally as 33.999999999... it will be truncated to 33.

Use round() if you need to perform rounding (3.9 → 4, 3.4 → 3).


Note:

  • 1234.34 is actually 1234.33999999999991814547684044... because it cannot be represented exactly using finite number of binary digits, so at the 53rd bit it will be rounded off
  • Hence your 0.34 is actually 0.33999999999991814547684044...,
  • Your 3.4 is actually 3.3999999999991814547684044...,
  • Your 34 is actually 33.999999999991814547684044...,
  • Your 340 is actually 339.99999999991814547684044...,
  • etc.
kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
3

Floating point arithmetic uses a finite sum of powers of two to represent arbitrary numbers. A number such as 3.4 which is not precisely a sum of powers of two may be rounded. In this case, it's rounded down slightly, to say 3.39996…. Then when you multiply, the result would be 33.9996…, which would be rounded down to 33 under round-to-zero rules.

C++ console I/O is smart enough to round to the nearest even number, in terms of how many decimal digits are displayed, but the internal math circuitry of the computer has no knowledge of such. It uses the full precision of the value, which in this case contains an error.

Try cout << setprecision( 20 ); to see the ugly truth.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
1

To help you understand what's going on, let me give you a very simple explanation of analogous problems using fixed numbers of decimal places. (The problems you are having are due to fixed binary places, which are harder to understand, but the problem is the same.)

The best you can do to represent 1/3 is .333333. But now 3 * 1/3 != 1.

You can represent 2/3 as .666666, and then 2 * 1/3 = 1/3 but then 2/3 + 1/3 != 1.

You can represent 2/3 as .666667, and then 2/3 + 1/3 = 1, but then
2/3 - 1/3 - 1/3 != 0 and 2 * 1/3 != 2/3.

You should not expect floating point math to produce exactly correct results, due to rounding and limited precision.

Just as 1/3 has no exact decimal representation, .34 has no exact binary representation.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
1

The trouble is your first assumption is false:

double num = 1234.34;
int numInt = num;
double numAfterPoint = num - numInt; // 0.34


std::cout << std::setprecision(17) << numAfterPoint << "\n";

3.3999999999991815

Now if you set the precision in your main loop you will get the following number.

3.3999999999991815 > 3 
33.999999999991815 > 33 
339.99999999991815 > 339 
3399.9999999991815 > 3399

The trouble is that the stream printing code is rounding the results before printing resulting in it printing 3.4 rather than 3.3999999999. This is because 3.4 can not be represented exactly by binary floating point numbers.

Martin York
  • 257,169
  • 86
  • 333
  • 562
0

Since decimal numbers are in general not exactly representable in binary, num is not 1234.34, but the closest double value to that number. That one may be slightly smaller than 1234.34 (say, 1234.33999999999999999999999); in that case, of course numAfterPoint is also slightly smaller than 0.34, making 100*numAfterPoints sightly smaller than 34 etc. Since conversion to int removes the fractional part, even if it is extremely close to 1, you'll then get 33 instead of 34.

On the other hand, if you output the float value directly, it is rounded to a specific number of digits (which you can control using stream manipulators). Therefore you don't see the difference unless you tell the stream to output very many digits. Try

std::cout << std::setprecision(20) << numAfterPoint << '\n';

to see what value is really stored.

celtschk
  • 19,311
  • 3
  • 39
  • 64