Skip to content

Instantly share code, notes, and snippets.

@chocolatkey
Last active June 15, 2018 19:06
Show Gist options
  • Save chocolatkey/ff9e2677a6b1b7a7a4e322a8233327ab to your computer and use it in GitHub Desktop.
Save chocolatkey/ff9e2677a6b1b7a7a4e322a8233327ab to your computer and use it in GitHub Desktop.
Collatz conjecture output to file
/**
* 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