Last active
October 3, 2016 15:15
-
-
Save willeccles/37d666ab754c9ff7a8c7d3e2f4487105 to your computer and use it in GitHub Desktop.
Calculate pi using n iterations, t threads, and d decimal places.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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