Skip to content

Instantly share code, notes, and snippets.

@willeccles
Last active October 3, 2016 15:15
Show Gist options
  • Save willeccles/37d666ab754c9ff7a8c7d3e2f4487105 to your computer and use it in GitHub Desktop.
Save willeccles/37d666ab754c9ff7a8c7d3e2f4487105 to your computer and use it in GitHub Desktop.
Calculate pi using n iterations, t threads, and d decimal places.
// compile with:
// g++ -O3 calcpi.cpp -o calcpi.o -std=c++11
// run with:
// ./calcpi.o <threads> <iterations> <decimal places>
// it's recommended to use multiple threads if possible, but to always specify iterations, as if you don't, it will take forever and a half.
// decimal places is completely optional, and goes up to 51. by default it uses 10 digits.
// NOTE: KEEP IN MIND THIS IS AN ESTIMATION. IT WILL BE USUALLY ACCURATE TO 10 OR SO DIGITS, BUT PAST THAT WILL TAKE MORE ITERATIONS.
// at the moment, time is bugged. if you run with one thread, it will be accurate,
// but with more than one, it will be wrong. This is because it counts user/cpu time, not real time.
// run the following to see an example of this:
// $ time ./calcpi.o 4 1000000000
#include <stdio.h>
#include <stdlib.h>
// these two are to get maximums
#include <limits.h>
#include <float.h>
#include <thread>
#include <future>
#include <ctime>
#include <cmath>
#include <iostream>
#include <iomanip> // for std::setprecision()
// max of long double: LDBL_MAX
long double denominatorParts[3] = {2.0, 3.0, 4.0};
long double pi = 3.0; // start with 3
unsigned long cycles = ULONG_MAX;
void calcinrange(unsigned long start, unsigned long end, std::promise<long double> && r, int TID) {
unsigned long cycle = start;
long double dParts[3] = {2.0+(long double)(start*2), 3.0+(long double)(start*2), 4.0+(long double)(start*2)};
long double pi = 0.0; // the smaller ones will start with 0, then they will all be added to 3 at the end
bool add = true;
while (cycle <= end) {
long double addend = 4.0/(dParts[0]*dParts[1]*dParts[2]);
if (add) pi += addend;
else pi -= addend;
for (int i = 0; i<3; i++)
dParts[i]+=2.0;
cycle++;
add = !add;
}
r.set_value(pi);
printf("Thread %d done.\n", TID);
}
int main(int argc, char* argv[]) {
int threads = 1;
int precision = 10;
if (argc >= 4) {
precision = std::abs(atoi(argv[3]));
if (precision > 51) {
printf("Warning: %d is equivalent to a precision of 51.\n", precision);
precision = 51;
}
threads = atoi(argv[1]);
cycles = strtoul(argv[2], NULL, 10);
} else if (argc == 3) {
threads = atoi(argv[1]);
cycles = strtoul(argv[2], NULL, 10);
} else if (argc == 2) {
threads = atoi(argv[1]);
}
printf("Calculating pi over %lu iterations.\nUsing %d threads.\nPrecision: %d decimal places.\n", cycles, threads, precision);
clock_t start = clock();
std::thread *t = new std::thread[threads];
std::promise<long double> *p = new std::promise<long double>[threads];
std::future<long double> *futures = new std::future<long double>[threads];
for (int i = 0; i < threads; i++)
futures[i] = p[i].get_future();
for (int TID = 0; TID < threads; TID++) {
// first iteration is 0, then the last is 'cycles'
unsigned long start = 0+(TID*(cycles/threads));
unsigned long end = start+(cycles/threads)-1;
t[TID] = std::thread(calcinrange, start, end, std::move(p[TID]), TID);
printf("Thread %d: %lu to %lu\n", TID, start, end);
}
printf("Started.\n");
long double *returns = new long double[threads];
for (int i = 0; i < threads; i++) {
t[i].join();
returns[i] = futures[i].get();
}
printf("Joined threads\n");
long double answer = 3.0;
for (int i = 0; i < threads; i++)
answer += returns[i];
std::cout << "Answer: " << std::setprecision(precision) << answer << std::endl;
clock_t time = clock()-start;
double elapsedtime = (double)time/(double)CLOCKS_PER_SEC;
std::cout << "Took " << std::setprecision(2) << elapsedtime << " seconds.\n";
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment