0

I'm beginning to teach myself C++ until my class starts in the fall. I was wondering if you might be able to help me come up with a better way to ask the user for the number of digits they want for the number pi, and then display it. My problem is that using pi = atan(1)*4 isn't precise past around 10 decimal places. Is there a better built in number that has pi to at least 20 decimal places? Here is what I have so far, thanks!

#include <iostream>
#include <string>
#include <iomanip>
#include <ios>
#include <sstream>
using namespace std;
using std::setprecision;
using std::streamsize;


int main()
{
    double pi = atan(1)*4;
    int input = 0;
    while(true)
    {
        cout << "Please enter how many digits of PI you would like to see (Max 20): ";
        cin >> input;
        if(input > 0 && input <= 20)
        {
            break;
        }
        else
        {
            cout << "That's not a valid number! Try again." << endl;
        }
    }
    streamsize prec = cout.precision();
    cout << setprecision(input);
    cout << "Here you go: " << pi <<endl;
    system("pause");
}
Mysticial
  • 464,885
  • 45
  • 335
  • 332
Binka
  • 111
  • 4
  • 11
  • 1
    Not one that fits into a `double`. A hardcoded string would probably be best for that few digits, to be honest. – chris Jul 09 '13 at 22:19
  • @rightfold, if you check for invalid content (I think that's what you want to do by adding `cin` to if statement) then you also need to `cin.clear()` – sasha.sochka Jul 09 '13 at 22:29
  • There are MANY series approximations that will do what you want and converge quickly (Google is your friend, try "approximations for pi"), as long as you are doing the computations in sufficient precision. A double will NEVER suffice here. –  Jul 09 '13 at 22:30
  • Consider using a long double... http://ideone.com/AsufUo – sehe Jul 09 '13 at 22:44
  • @sehe, The funny thing is that the second last digit should be a 2, so the algorithm is still too imprecise for 20. – chris Jul 09 '13 at 22:50
  • @chris Algorithm, what algorithm ? :) – sehe Jul 09 '13 at 22:53
  • @sehe, I would consider the calculation to be a very simple one, but that might just be me. I couldn't think of any better word, like you know, calculation, at the time. – chris Jul 09 '13 at 22:55
  • @chris the characteristics of this solution are mainly the data representation, not the algorithm (`atan(1)*4` is simply `constexpr` evaluated by the compiler and emitted into the object file at compiletime: http://paste.ubuntu.com/5859984/, line 58+) – sehe Jul 09 '13 at 23:04
  • @sehe, Interesting, I thought `long double` would at least hold 20, but I was never sure how many places it usually had. – chris Jul 09 '13 at 23:06
  • 1
    @sehe Although I can't find it anymore, I've seen a very clever < 200 byte C program that will compute up to a few thousand digits of Pi. It can tweaked to go higher, but runs in polynomial time. If I ever get the time, I want to build a very light-weight open-sourced C++11 program that will run in quasi-linear time. Sorta like a miniature version of my big program - except nowhere near as fast or as memory efficient. – Mysticial Jul 09 '13 at 23:06
  • @Mysticial this one is particularly nice: [endoh2.c](http://www.ioccc.org/2012/endoh2/endoh2.c) which is a [self replicating program and pi or e computation](http://www.ioccc.org/2012/endoh2/hint.html). Oh and builting ascii-art font. And pretty code. It's magic. – sehe Jul 09 '13 at 23:14

3 Answers3

14

The easiest way to do this would probably just have a std::string containing the digits that you want ("3.14159265358979323846264338327950288419"), and then just print the first input digits beyond the decimal point.

Jashaszun
  • 9,207
  • 3
  • 29
  • 57
  • 1
    True, this could be very easy, but it just seems like a cheap way of solving the problem :) – Binka Jul 09 '13 at 22:24
  • 2
    Hey, judging from the formatting of the question, I thought you'd appreciate a cheap solution. (_Bummer, that's probably over the line_) – sehe Jul 09 '13 at 22:26
  • Performance will be excellent but you can avoid the heap allocation and just use a `const char*` – Pete Jul 09 '13 at 22:26
  • @Binka Would you rather worry about using an arbitrary-precision library for C++? :) – Jashaszun Jul 09 '13 at 22:27
  • 3
    @Binka So. How many digits do you want to support up to? If it's anything less than a few million, then this answer is probably the easiest. :) – Mysticial Jul 09 '13 at 22:30
4

I would say that this is less of a C++ problem, and more of a math problem. There are several infinite series that converge to the true value of Pi very quickly. Have you looked at the Wikipedia article on this topic?

As for being precise to nine or ten digits, you may run into rounding issues using double (especially with certain calculation methods). I would consider looking into an arbitrary-precision math library. I'm a big fan of MPFR, but I'm sure Boost has something analogous if that's more your thing (keep in mind that Boost is a C++ library, whereas MPFR is a C library [although you can, of course, use C code from C++]).

MPFR does have a C++ wrapper, but in general I don't enjoy using it as much as the C functions, since the last time I looked at it (admittedly, a while ago), it wasn't quite as feature-complete.

It's probably worth noting also that, since your goal is to learn C++, and not to learn how to efficiently approximate Pi, it might be preferrable to solve this problem by e.g. just retrieving the first n-digits from a hard-coded string instead, as Chris said.

CmdrMoozy
  • 3,870
  • 3
  • 19
  • 31
0

A double will have 53 bits of precision. Each bit gives about 1/3 of a decimal digit (log(10)/log(2) to be precise), which means that we get approximately 53/3 digits out of a double. That should give 17 digits (including the 3 at the beginning). It's plausible that atan(1) isn't giving quite all the digits of pi/4 either (because atan as well as any other trigonometric function is an approximation).

If you want many more digits than about 12-14 digits, you will need to use a "big number" library, and there are a number of "clever" ways to calculate the decimals of PI.

David G
  • 94,763
  • 41
  • 167
  • 253
Mats Petersson
  • 126,704
  • 14
  • 140
  • 227