0

WHy is below code not giving proper output till requested precision? Please note that since i am using std::fixed so i am expecting precision to be representing digits after decimal points. Hope thats correct?

#include <iostream>
#include <limits>
#include <cmath>
#include <iomanip>

int main()
{
    double d3 = 50388143.0682372156805328369140625;
    std::cout << "d3 = " << d3 << std::endl; 
    std::cout << std::setprecision(17) << std::fixed << "d3 = " << d3 << std::endl; 
    std::cout << std::setprecision(20) << std::fixed << "d3 = " << d3 << std::endl; 
}

Produces output as

d3 = 5.03881e+07
d3 = 50388143.06823721528053284   // See its different than original floating point
d3 = 50388143.06823721528053283691 // See its different than original floating point

Why isn't the output coming as

d3 = 5.03881e+07
d3 = 50388143.06823721568053283
d3 = 50388143.06823721568053283691

I was expecting the output digits to match with input digits till requested precision but its not the case. Why so?

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
Test
  • 564
  • 3
  • 12
  • 2
    `double` is accurate to about 15 decimal digits. You can't expect it to be more precise than that. Consider: your literal has 33 decimal digits - that's `33/log(2)` or about 109 bits of information. But `sizeof(double) == 64` – Igor Tandetnik Aug 14 '21 at 17:47
  • @IgorTandetnik - Can you explain this a bit more? What do you mean by "accurate to about"? Isn't there a deterministic value? How can i find out exact value to which it will be accurate? How does 109 bits map to 64 bits and then we get 15? – Test Aug 14 '21 at 17:50
  • 2
    There's a finite number of values representable in a `double` (since it consists of a finite number of bits), whereas there's an infinite number of real values. When the compiler parses your long literal, it has to find a value that is closest to the exact mathematical value of that literal among all values representable in a `double`. That approximate value is expected to match the first 15 significant digits of the literal; after that, you observe rounding error. – Igor Tandetnik Aug 14 '21 at 17:56
  • 1
    See also: [Is floating point math broken?](https://stackoverflow.com/questions/588004) – Igor Tandetnik Aug 14 '21 at 17:57
  • @IgorTandetnik - is their any c++ helper macro or something available which can tell me what will be the significant digits upto which the type will be accurate? – Test Aug 14 '21 at 17:59
  • 1
    You may be looking for [`std::numeric_limits::digits10`](https://en.cppreference.com/w/cpp/types/numeric_limits/digits10) – Igor Tandetnik Aug 14 '21 at 18:05
  • @IgorTandetnik - Perfect. Thanks. I realized there is something like numeric_limits::max_digits10 also there. What's that for now? – Test Aug 14 '21 at 18:08
  • 1
    `digits10` is how many decimal digits a floating-point type can represent without loss: for every distinct number consisting of no more than `digits10` decimal digits, there's a distinct floating point value nearest to it. `max_digits10` is the other way round: how many digits do you need to have a distinct decimal value for every representable floating-point value. For `double`, I think `digits10 == 15` and `max_digits10 == 16` – Igor Tandetnik Aug 14 '21 at 18:14
  • 1
    You asked where the number 15 comes from. On a typical implementation, `double` is 64-bits large, of which 53 bits are used for mantissa (and the rest is the sign bit and exponent). 53 bits can represent `53*lg(2)` or `15.95...` decimal digits. – Igor Tandetnik Aug 14 '21 at 18:16

1 Answers1

0

d3 does not have the value OP expects.


double is typically a 64-bit object and so can exactly represent about 264 different values.

50388143.0682372156805328369140625 is not one of them.

Typical double is encoded as an integer (less than 253) times some power of 2. See dyadic rational.

The closest double is 1690745520189437 * pow(2,-25) or

50388143.068237215_2805328369140625   // closest double
50388143.068237215_6805328369140625   // OP's original code.
50388143.068237222_731113433837890625 // next best double

Printing 50388143.068237215_2802805328369140625 with setprecision(17) is expected to be:

50388143.06823721528053284

as seen by OP.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • why is your little lower having higher value? And how did 2 change to 6? – Test Aug 14 '21 at 18:04
  • thanks. All understood except this line "The closest double is 1690745520189437 * pow(2,-25)". How is this figure arrived at? – Test Aug 14 '21 at 18:34
  • 1
    @Test, One method, keep doubling `50388143.0682372156805328369140625` until it is an integer and still less than 2^53. Given 25 digit fraciton of .0682372156805328369140625, that takes at least 25 doublings. – chux - Reinstate Monica Aug 14 '21 at 18:36