F
Fei Liu
Hello, the following code is an implementation computing the 3n+1
problem, specifically maximum number of steps to complete for any
integer range. The algorithm aims to be as efficient/fast as possible.
One thing I am unsatisfied of is the use of hash_map (deprecated but
supported by most C++ vendors). Is there a portable hash map
implementation? I am tempted to use unordered_map with boost::hash. I
didn't use std::map because std::map lookup/insertion is O(lgN) while
hash map is O(1). What's your opinion? Comments about style etc are
welcome as well regarding other aspects of my implementation.
Fei
#include <iostream>
#include <fstream>
#include <algorithm>
using namespace std;
#include <ext/hash_map>
using namespace __gnu_cxx;
#include <boost/filesystem/convenience.hpp>
hash_map<unsigned int, unsigned int, hash<unsigned int> > steps;
// Computes number of steps for number n according
// to Collatz Conjecture (3n+1 problem)
// http://en.wikipedia.org/wiki/Collatz_conjecture
//
// To speed things up, results are book kept, saved/restored
// when program starts/finishes.
//
// In the recursively computing function, the steps to finish a
// a number is always memorized and retrieved on demand.
unsigned int compute_steps(int n){
// shortcut to retrieve memorized steps[n]
if(steps[n])
return steps[n];
if(n == 1) return 1;
if(n%2)
n = 3*n+1;
else
n = n/2;
cout << ' ' << n;
// shortcut to memorize steps[n]
steps[n] = compute_steps(n);
return steps[n] + 1;
}
int main(){
boost::filesystem:ath file("record_h.txt");
unsigned int two[2];
if(exists(file)){
ifstream inf("record_h.txt", ios::binary);
while(inf.read((char *)two, 2*sizeof(unsigned int)))
steps[two[0]] = two[1];
inf.close();
}
int i, j;
// It's not as easy as it seems to safely read integers from cin
// The following trick makes sure a pair of integers are read in safely
while(!(cin >> i >> j)) {
cout << i << ' ' << j << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
assert(i != 0 && j >= i);
// compute steps for each l between i and l and prints its value
for(int l = i; l <= j; l ++){
cout << l << ": ";
steps[l] = compute_steps(l);
cout << '\n';
}
// compute some statitics of the result, the largest number n
steps[n] is computed
// the number of 0s from steps to steps+rbegin
unsigned int max_step = 0;
ofstream ofs("record_h.txt", ios::binary);
two[0] = it->first;
two[1] = it->second;
max_step = (max_step > it->second) ? max_step : it->second;
ofs.write((const char *)two, 2*sizeof(unsigned int));
++it;
}
ofs.close();
cout << "maximum step: " << i << ' ' << j << ' ' << max_step << '\n';
}
problem, specifically maximum number of steps to complete for any
integer range. The algorithm aims to be as efficient/fast as possible.
One thing I am unsatisfied of is the use of hash_map (deprecated but
supported by most C++ vendors). Is there a portable hash map
implementation? I am tempted to use unordered_map with boost::hash. I
didn't use std::map because std::map lookup/insertion is O(lgN) while
hash map is O(1). What's your opinion? Comments about style etc are
welcome as well regarding other aspects of my implementation.
Fei
#include <iostream>
#include <fstream>
#include <algorithm>
using namespace std;
#include <ext/hash_map>
using namespace __gnu_cxx;
#include <boost/filesystem/convenience.hpp>
hash_map<unsigned int, unsigned int, hash<unsigned int> > steps;
// Computes number of steps for number n according
// to Collatz Conjecture (3n+1 problem)
// http://en.wikipedia.org/wiki/Collatz_conjecture
//
// To speed things up, results are book kept, saved/restored
// when program starts/finishes.
//
// In the recursively computing function, the steps to finish a
// a number is always memorized and retrieved on demand.
unsigned int compute_steps(int n){
// shortcut to retrieve memorized steps[n]
if(steps[n])
return steps[n];
if(n == 1) return 1;
if(n%2)
n = 3*n+1;
else
n = n/2;
cout << ' ' << n;
// shortcut to memorize steps[n]
steps[n] = compute_steps(n);
return steps[n] + 1;
}
int main(){
boost::filesystem:ath file("record_h.txt");
unsigned int two[2];
if(exists(file)){
ifstream inf("record_h.txt", ios::binary);
while(inf.read((char *)two, 2*sizeof(unsigned int)))
steps[two[0]] = two[1];
inf.close();
}
int i, j;
// It's not as easy as it seems to safely read integers from cin
// The following trick makes sure a pair of integers are read in safely
while(!(cin >> i >> j)) {
cout << i << ' ' << j << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
assert(i != 0 && j >= i);
// compute steps for each l between i and l and prints its value
for(int l = i; l <= j; l ++){
cout << l << ": ";
steps[l] = compute_steps(l);
cout << '\n';
}
// compute some statitics of the result, the largest number n
steps[n] is computed
// the number of 0s from steps to steps+rbegin
unsigned int max_step = 0;
ofstream ofs("record_h.txt", ios::binary);
while(it != steps.end()){hash_map said:::const_iterator it = steps.begin();
two[0] = it->first;
two[1] = it->second;
max_step = (max_step > it->second) ? max_step : it->second;
ofs.write((const char *)two, 2*sizeof(unsigned int));
++it;
}
ofs.close();
cout << "maximum step: " << i << ' ' << j << ' ' << max_step << '\n';
}