Daemon Beast
Daemon Beast

Reputation: 2909

How to make a float in c++ without a decimal place limit

I have a c++ program which calculates Pi but then its value gets cut off after a few decimal places because of the decimal place limit on the float which Pi is stored in.

I've already tried using different data types instead of float but they still have a decimal place limit which is too small.

#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;

int main(){
    cout << "Calculate Pi using the Nilakantha series" << endl << endl;

    unsigned long int iterations = 0;
    unsigned long int x = 0;
    unsigned long int y = 2;
    char z = 0;
    string fileName = "";
    int64_t Pi = {3.0f};

    cout << "Input the number of loop iterations(maximum of 4,294,967,295): ";
    cin >> iterations;
    cout << "Input the name of the file you want to write to: ";
    cin >> fileName;

    for(x = 0; x < iterations; x++){
        Pi += 4.0f / (y * (y + 1.0f) * (y + 2.0f));
        y += 2;
        Pi -= 4.0f / (y * (y + 1.0f) * (y + 2.0f));
    y += 2;
    }

    ofstream file;
    file.open(fileName + ".txt");
    file << Pi;
    file.close();

    cout << endl << "Calculation complete, check the file " << fileName << ".txt";

    cin >> z;
}

How do I remove the limit or use a method which stores the value of Pi without it getting cut off after a few decimal places?

Upvotes: 2

Views: 345

Answers (2)

einpoklum
einpoklum

Reputation: 131547

(I'm ignoring some of the less fundamental issues which @JAntonioPerez points out in his fine answer and focusing on what I find to be the core of this question.)

If you just need a few more decimal digits of precision, then use double or long double instead of float.

If you want much higher precision, or a precision which can be specified as a run-time or compile-time arbitrary value, then you need something else. Either:

  1. Use an arbitrary-precision number data type; here is a list of libraries providing such types.
  2. Instead of iterating over the entire number, use iteration to determine the value of individual digits/characters in the output; and write the digits you obtain to the output file one at a time (or a few at a time).

Of course, both options are rather involved and are probably not appropriate for a "toy program" like you seem to be writing.

Upvotes: 2

Alecto
Alecto

Reputation: 10740

There are a few big issues here. The first is that you're using std::cout to print the value, and std::cout only prints 6 digits by default. The second is that you declared Pi as an int64_t. That means you'll get at most 1 digit of precision, since Pi is an integer. You need to have it as a floating point type.

So how many digits will you get from each type?

  • 6 digits from float
  • 15-16 digits from double
  • 20 digits from long double on clang and gcc, but only 15-16 in Visual Studio
  • Around 30 digits from GCC's __float128, although that one only works on GCC

If you want more precision than that, you're going to have to use a high-precision arithmetic library that gives you more digits by simulating it. It won't be as fast, but it'll do the job.

You can play around with the amount of precision with each type using this code. I templated calculatePi on the type, so you can just stick in float, double, long double, or __float128. It'll print 20 digits. This code should print all 20 digits correctly for __float128.

#include <cstdio>
using namespace std;

template<class Float>
Float calculatePi(size_t iterations) {
    Float y = 2;
    Float Pi = 3;
    const Float two = 2;
    const Float four = 4;
    const Float one = 1;

    for(size_t i = 0; i < iterations; i++) {
        Pi += four / (y * (y + one) * (y + two));
        y += two;
        Pi -= four / (y * (y + one) * (y + two));
        y += two;
    }
    return Pi; 
}
int main(){
    long double result = calculatePi<long double>(1000000); 

    printf("Expected: 3.14159265358979323846\n"); 
    printf("Actual:   %.20Lf", result); 
}

Upvotes: 3

Related Questions