Search code examples
c++stringstringstreamistringstream

istringstream rounds long numbers - how can I prevent that ?


Given the following code :

istringstream i("2.11099999999999999999");

double d;
if (!(i >> d)) {d = 0;}

cout << d << endl;

The output is 2.111 .

I want to have the ability of working with long numbers , float numbers (floating point included) , however when I convert my istringstream to double , I get a rounded number .

How can I prevent that ? How can I keep the given input as-is ?

Regards


Solution

  • In this case, you can't prevent it. double is not capable of precisely representing the value 2.11099999999999999999, and none of the values it can represent distinguishes 2.11099999999999999999 from 2.111.

    http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html should tell you what you need to know, and possibly more.

    If you use a different example, where double can represent values that distinguish between the rounded and unrounded value, then you could do this:

    #include <iostream>
    #include <sstream>
    #include <iomanip>
    
    int main() {
        std::istringstream iss("2.1109999");
        double d;
        iss >> d;
        std::cout << d << "\n";
        std::cout << std::setprecision(10) << d << "\n";
    }
    

    Output:

    2.111
    2.1109999
    

    You should be aware, though, that the value stored in d is not exactly 2.1109999:

    std::cout << std::setprecision(20) << d << "\n";
    

    Output (on my machine, yours may differ because some runtime libraries don't print to 20 s.f at all):

    2.1109998999999999292
    

    That's because double stores values in binary, not decimal. So it can only represent terminating binary fractions. 2.1109999 is not a terminating binary fraction for basically the same reason that one third is not a terminating decimal fraction.

    So, there are two ways to keep the given input as-is (i.e. to represent that number precisely):

    1. don't convert to double, leave it as a string.
    2. don't convert to double, instead find or write a library that represents decimal fractions and/or rational numbers. For example, the GMP library has mpq_t or there's Boost.Rational.