Search code examples
c++precisionistreamextractor

C++ istream extractor precision?


I am reading from a text file which contains the following line:

      deltaT          0.005;

Once I've got the correct line within a string, I want to read out the value with code like this:

      double deltaT;
      stringstream ss(line);
      ss >> tag;                //Contains:         deltaT
      ss >> deltaT;             //Should contain:   0.005

During debugging, I see that deltaT contains: 0.0050000000000000001

So is there a way to set the "precision" of the extractor like there is for a stream inserter?

Or what is the best way to guarantee that the value in the text file is the double value I have in my program.

Thanks, Madeleine.


Solution

  • That's the usual problem of binary floating point types: 0.005 isn't exactly representable by a double, so the conversion from the "decimal literal" yields the most similar number representable by a double.

    There's no solution if you want to use double or other finite, binary floating point types, since 0.005 has a finite form in decimal, but is periodic in binary (and the mantissa of any FP type is limited).

    To see how is this possible, consider the fraction 1/3: in base 3 it has a finite representation, while in base 10 it's periodic:

    (1/3)10 = 0.33333...10 = 0.13

    now, any "regular" floating point type has only some limited space for the mantissa (i.e. the significant digits to store), so every periodic number has to be truncated (actually rounded) at some point; this results in the loss of precision you see.

    Notice that several "arbitrary precision libraries" are available to deal with this kind of problems and do math with precision limited only by the available memory (e.g. GMP), but you should consider if the additional complexity/loss in performance is actually justified by the gain in precision.

    Another solution (commonly used when doing calculations that involve money) is to use fixed-precision types, that store the amount as an integer "implicitly scaled" by some decimal factor (the concept is that you store cents as integers instead of dollars as float or whatever); this avoids any surprise deriving from the decimal to binary conversion, since all integers are exactly representable with a limited number of digits in any base.