2
#include <iostream>
#include <iomanip>
#include <limits>

using namespace std;

int main() {
    const long double longDoublePI = 3.141592653589793238;
    cout << setw(16) << "longDoublePI = " << setprecision(numeric_limits<long double>::digits10 + 1) << longDoublePI << endl;

    return 0;
}

But the result output is:

longDoublePI = 3.141592653589793116

Why the answer is wrong?

Ann
  • 33
  • 5
  • 1
    Because 3.141592653589793116 is the `double` nearest to 3.141592653589793238. – molbdnilo Apr 05 '17 at 16:37
  • 3
    Short answer: expecting exact results from floating-point approximations is a surefire recipe for disappointment. –  Apr 05 '17 at 16:37
  • 1
    In what sense is the answer wrong? It's not accurate enough for you? How accurate are you expecting it to be and why? – David Schwartz Apr 05 '17 at 16:40
  • But it is long double type, it should be more precise than double. Moreover, I set the most precision for long double, numeric_limits::digits10 + 1. – Ann Apr 05 '17 at 16:42
  • 2
    `longDoublePI` is a `long double` but `n.nnnnn` is a `double` unless you tell the compiler otherwise. – NathanOliver Apr 05 '17 at 16:42
  • 1
    @Ann A very important rule to understand in both C and C++ is that what you do with a result has no effect on how that result is computed. C++'s type system and promotion rules are complex enough without adding all the possible additional wrinkles that would add. – David Schwartz Apr 05 '17 at 16:44
  • 2
    Read more about [floating point literals](http://en.cppreference.com/w/cpp/language/floating_literal), pay close attention to the *suffixes*. – Some programmer dude Apr 05 '17 at 16:44
  • The problem is that the type of the literal `3.141592653589793238` is just double; the type of `longDoublePI` doesn't change that. Try `3.141592653589793238L`. – H Walters Apr 05 '17 at 16:44
  • I think I got it! – Ann Apr 05 '17 at 16:44
  • All of these answers in the comments section. Sigh. – Lightness Races in Orbit Apr 05 '17 at 18:07
  • A must read: [What Every Computer Scientist Should Know About Floating-Point Arithmetic](https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html). – Thomas Matthews Apr 05 '17 at 18:38
  • this is not a dupe of https://stackoverflow.com/questions/588004/is-floating-point-math-broken that question is about the general accuracy issues with FP. This question is about failing to designate the FP literal as being a `long double` by suffixing it with `L`. – Oliver Schönrock Dec 13 '20 at 12:09

2 Answers2

5

Because, although longDoublePI is a long double, the literal from which you initialised it is only a double, which does not have as much precision.

You can use this instead:

const long double longDoublePI = 3.141592653589793238L;
//                                                   ^
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • Note that this is a particular trap when using the M_PI macro. You can't append an 'L' to that, so it is always inaccurate to initialise `long double` varable with M_PI or to use M_PI in a `long double` calculation. – Oliver Schönrock Dec 13 '20 at 12:06
2

For a start, this is platform dependent. The standard (C++14, 3.9.1 Fundamental types [basic.fundamental] para 8) stipulates that long double only has at least as much precision as float. In practice, I would expect it to have the same or more precision than double, at least on desktop/server platforms.

Generally I would use standard macros like M_PI to get well-known constants. I don't know of any standard long double versions, though GNU seems to have M_PIl as a non-standard extension.

Finally, other than M_PI, the standard trick to get pi is to use

4.0L*std::atan(1.0L)

See here for more discussion.

Paul Floyd
  • 5,530
  • 5
  • 29
  • 43