Rounding problem with double type

19,449

Solution 1

In the set of double values, there is no such thing as the number 1.11 because internally, double uses a binary representation (as opposed to humans who are used to a decimal representation). Most finite decimal numbers (such as 1.11) have an infinite representation in binary, but since memory is limited, you lose some precision because of rounding.

The closest you can get to 1.11 with the double data type is 1.1100000000000000976996261670137755572795867919921875, which is internally represented as 0x3ff1c28f5c28f5c3.

Your requirement of two decimal places sounds like you are working with money. A simple solution is to store the cents in an integer (as opposed to the dollars in a double):

int cents = 111;

This way, you don't lose any precision. Another solution is to use a dedicated decimal data type.

Solution 2

the floating-point types like float and double are not 100% precise. They may store 14.3 as 14.299999... and there is nothing wrong about that. That is why you should NEVER compare two floats or doubles with == operator, instread you should check if the absolute value of their difference is smaller than a certain epsilon, like 0.000000001

Now, if you want to output the number in a pleasant way, you can use setprecision from <iomanip>

E.g.

#include <iostream>
#include <iomanip>

int main()
{
   double d = 1.389040598345;
   std::cout << setprecision(2) << d; //outputs 1.39
}

If you want to obtain the value of d rounded 2 decimal places after the point, then you can use this formula

d = floor((d*100)+0.5)/100.0; //d is now 1.39

Solution 3

Not every decimal number has an exact, finite, binary floating-point representation. You've already found one example, but another one is 0.1 (decimal) = 0.0001100110011... (binary).

You either need to live with that, or use a decimal floating-point library (which will be less efficient).

My recommendation would be to store numbers to full precision, and only round when you need to display them to humans.

Share:
19,449
Anish Kurian
Author by

Anish Kurian

Updated on June 04, 2022

Comments

  • Anish Kurian
    Anish Kurian almost 2 years

    Possible Duplicate:
    Why don't operations on double-precision values give expected results?

    I am experiencing a peculiar problem in C++. I created a variable of type Double. Then I did some calculations with some values assigned to other variables and assigned the result to the double variable I declared. It gave me a result with a long decimal part. I want it to round to only 2 decimal places. and store it into the variable. But even after several attempt rounding, I couldnt round it to 2 decimal places.

    Then I tried another way to check what the real problem is. I created a Double variable and assigned it the value 1.11. But when I debugged it by putting a break point and added a watch for that variable, I could find that the value now stored in the variable is 1.109999999999.

    My question is, why is it showing like that? Isnt there any way in which we can round the variable into two decimal places? Why is it showing a long decimal part even if we assign a number with just two decimal places?

    Please suggest a way to store numbers - whether it is calculated or directly assigned - as it is, in a double variable rather than a number with a long decimal part.

    • Šimon Tóth
      Šimon Tóth over 13 years
      Don't use floating point arithmetic for fixed point calculations.
    • Nikhil Dinesh
      Nikhil Dinesh over 8 years
      double d = 1.3894637; int i = ceil(d*10);
  • Martin York
    Martin York over 13 years
    That depends on usage. Financial institutions take a dim view on any rounding errors (especially if it benefits the customer). Thus if you are doing anything with money you need a decimal type.
  • fredoverflow
    fredoverflow over 13 years
    Casting to int is a very bad idea, because most double values are too large to fit in the set of integers. I suggest calling floor instead.
  • Armen Tsirunyan
    Armen Tsirunyan over 13 years
    @FredOverflow: Ok, agree, changing