Last active
June 15, 2018 19:06
-
-
Save chocolatkey/ff9e2677a6b1b7a7a4e322a8233327ab to your computer and use it in GitHub Desktop.
Collatz conjecture output to file
This file contains 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
/** | |
* Collatz conjecture (multithreaded, C++) | |
* chocolatkey 2016 | |
*/ | |
// STUFF YOU CAN CHANGE | |
#define MAX_THREADS 512 // For self-restraint | |
#define MODE 0 // 0 = RAM storage (warning: can eat up ram quickly with calculations > 1000000 iterations), 1 = HDD split files storage (very low RAM usage, but more disk r/w)) | |
// END OF STUFF | |
#include <stdlib.h> | |
#include <iostream> | |
#include <fstream> | |
#include <sstream> | |
#include <vector> | |
#include <thread> | |
using namespace std; | |
typedef unsigned int uint; // Just to make my life easier | |
typedef vector<uint> Vector; // 1D uint Vector | |
typedef vector<Vector> TwoVector; // 2D Vector | |
TwoVector cseq; // For RAM array | |
/** | |
* Collatz thread function | |
* @param tid Thread number | |
* @param x First seed | |
* @param y Last seed | |
* @param y Step | |
*/ | |
void collatz(uint tid, uint x, uint y, uint z) { | |
#if MODE == 1 | |
ofstream file; | |
string fname = string("output") + to_string(tid + 1) + string(".txt"); | |
file.open(fname); | |
stringstream msg; | |
msg << "#" << tid + 1 << " (" << x + 1 << "-" << y - 1 << ")" << endl; // So that output isn't garbled with other threads | |
cout << msg.str(); | |
uint s = x + z; | |
while(s < y) | |
{ | |
uint ss = s; | |
//int size = 0; | |
Vector seq; | |
while(ss != 1) | |
{ | |
if((ss % 2) == 0) | |
{ | |
ss /= 2; | |
} else | |
{ | |
ss = (3 * ss) + 1; | |
} | |
seq.push_back(ss); | |
} | |
file << s << "|" << seq.size() << "|"; | |
for (Vector::const_iterator i = seq.begin(); i != seq.end(); ++i) | |
{ | |
file << *i; | |
if(i != seq.end()-1) | |
file << ","; | |
} | |
if(s != (y-1)) // Who wants a useless \n at the end of their output? Not me. | |
file << endl; | |
s = s + z; | |
// Example: [4][2.0, 1.0][2] | |
~ss; | |
} | |
file.close(); | |
#else | |
// Write to RAM (vector array) | |
stringstream msg; | |
msg << "#" << tid + 1 << " (" << x + 1 << "-" << y - 1 << ")" << endl; // So that output isn't garbled with other threads | |
cout << msg.str(); | |
uint s = x + z; | |
while(s < y) | |
{ | |
uint ss = s; | |
while(ss != 1) | |
{ | |
if((ss % 2) == 0) | |
{ | |
ss /= 2;//>>= 1 | |
} else | |
{ | |
ss = (3 * ss) + 1; | |
} | |
cseq.at(s-1).push_back(ss); | |
} | |
s = s + z; | |
~ss; | |
} | |
#endif | |
} | |
/** | |
* Main function | |
* @param argc Length arg array | |
* @param argv Arg array | |
* @return | |
*/ | |
int main(int argc, char* argv[]) { | |
if(argc < 4) { | |
cout << "Collatz Conjecture Generator by Henry Stark (2016)\n" | |
"Usage: " << argv[0] << " <seedmin> <seedmax> <step> [threads]" << endl; | |
exit(-1); | |
} | |
uint x,y,z,num_threads; | |
// Parse arguments | |
for (int i = 1; i < argc; ++i) { | |
istringstream ss(argv[i]); | |
int nvar; | |
if (!(ss >> nvar)) | |
{ | |
cerr << "Invalid number " << argv[1] << endl; | |
exit(1); | |
} | |
switch (i){ | |
case 1: | |
x = nvar; | |
break; | |
case 2: | |
y = nvar; | |
break; | |
case 3: | |
z = nvar; | |
case 4: | |
if(nvar > MAX_THREADS) { | |
cerr << "# of threads specified (" << nvar << ")" | |
"larger than safe max (" << MAX_THREADS << ")"; | |
exit(1); | |
} else if(nvar > y) { | |
cerr << "# of threads specified (" << nvar << ")" | |
"exceeds # of calculations (" << (y) << ")"; | |
exit(1); | |
} else if(nvar == 0) { | |
num_threads = 1; | |
} else { | |
num_threads = nvar; | |
} | |
} | |
if((x + z) < 1) | |
{ | |
cout << "Starting point smaller than 1!" << endl; | |
exit(1); | |
} | |
} | |
// Set up threading | |
thread t[num_threads]; | |
uint nx[num_threads]; | |
uint ny[num_threads]; | |
uint numpcalcs = y - x + 1; | |
#if MODE == 0 | |
cseq.resize(numpcalcs); | |
#endif | |
uint perthread = numpcalcs / num_threads; | |
uint beg = x; | |
for (int i = 0; i < num_threads; ++i) { | |
nx[i] = beg - 1; | |
beg += perthread; | |
ny[i] = beg; | |
if(i == 0) {// First thread gets modulo. For last: (i + 1) == num_threads | |
// Final iteration (last thread gets modulo) | |
ny[i] += (numpcalcs % num_threads); | |
} | |
} | |
// Launch threads | |
for (int i = 0; i < num_threads; ++i) { | |
t[i] = thread(collatz, i, nx[i], ny[i], z); | |
} | |
// Join the threads with the main thread | |
for (int i = 0; i < num_threads; ++i) { | |
t[i].join(); | |
} | |
// Output | |
stringstream fnp; | |
fnp << "collatz_" << x << "_" << y << "_" << z << ".txt"; // File name with properties of collatz conjecture | |
ofstream finalfile(fnp.str(), ios_base::binary); | |
#if MODE == 1 | |
// Merge temp files from disk | |
cout << "Done collatzing. Merging files..." << endl; | |
for (int i = 1; i <= num_threads; ++i) { | |
cout << i << "..."; | |
stringstream fname; | |
fname << "output" << i << ".txt"; | |
ifstream thishtread(fname.str(), ios_base::binary); | |
finalfile << thishtread.rdbuf(); // Write thread output to final file | |
remove(fname.str().c_str()); // Probably won't work | |
} | |
#else | |
// Output from RAM Array | |
cout << "Done collatzing. Writing to file..."; | |
uint rowiteration = 1; | |
for(Vector& row:cseq){ | |
finalfile << rowiteration << "|" << row.size() << "|"; | |
uint coliteration = 1; | |
for(uint& col:row){ | |
finalfile << col; | |
if(coliteration != row.size()) | |
finalfile << ","; | |
coliteration++; | |
} | |
if(rowiteration != cseq.size()) // Who wants a useless \n at the end of their output? Not me. | |
finalfile << endl; | |
rowiteration++; | |
} | |
//////////////////////////////////////////////////////////////////////////////////////// | |
#endif | |
cout << endl << "Output: " << fnp.str() << endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment