blob: af8703ca4062da708f1f138b1e71fd828fd93c29 [file] [log] [blame]
// ###########################################
// [C++] Computing very long Fibonacci numbers
// Version 2.5.1 (with performance test)
// -------------------------------------------
// Created by Alex Vinokur
// http://up.to/alexvn
// ###########################################
// http://groups.google.com/groups?selm=bo4nls%2417vfq6%241%40ID-79865.news.uni-berlin.de
#include <climits>
#include <cstdlib>
#include <cassert>
#include <string>
#include <sstream>
#include <vector>
#include <iostream>
#include <iomanip>
#include <algorithm>
using namespace std;
#define MAX_VALUE(x,y) ((x) > (y) ? (x) : (y))
#define ASSERT(x)
// #define ASSERT(x) assert(x)
#define MAX_UNIT_VALUE (ULONG_MAX >> 2)
#define BASE1 10
#define BASE2 1000000000 // BASE1 ** (BASE1 - 1)
#if (BASE2 >= MAX_UNIT_VALUE)
#error Compilation Error-1 : (BASE2 >= MAX_UNIT_VALUE)
#endif
#if (!(BASE1 * (BASE2/BASE1 + 1) < MAX_UNIT_VALUE))
#error Compilation Error-2 : (!(BASE1 * (BASE2/BASE1 + 1) < MAX_UNIT_VALUE))
#endif
typedef unsigned int uint;
typedef unsigned long ulong;
// =========
class BigInt
// =========
{
friend ostream& operator<< (ostream& os, const BigInt& ins_i);
private :
static ulong head_s;
vector<ulong> units_;
public :
BigInt (ulong unit_i)
{
ASSERT (unit_i < BASE2);
units_.push_back (unit_i);
}
BigInt (BigInt big1_i, BigInt big2_i)
{
const ulong max_size = MAX_VALUE (big1_i.units_.size (), big2_i.units_.size ());
big1_i.units_.resize(max_size);
big2_i.units_.resize(max_size);
units_.resize(max_size);
head_s = 0;
transform (big1_i.units_.begin(), big1_i.units_.end(), big2_i.units_.begin(), units_.begin(), *this);
if (head_s) units_.push_back (head_s);
}
ulong operator() (const ulong n1, const ulong n2)
{
const ulong value = n1 + n2 + head_s;
head_s = value/BASE2;
return (value%BASE2);
}
};
// --------------
inline ostream& operator<< (ostream& os, const BigInt& ins_i)
{
ASSERT (!ins_i.units_.empty ());
for (ulong i = (ins_i.units_.size () - 1); i; --i)
{
os << ins_i.units_ [i] << setw (BASE1 - 1) << setfill ('0');
} return os << ins_i.units_ [0];
}
// ============
class Fibonacci
// ============
{
private :
vector<BigInt> fibs_;
BigInt get_number (uint n_i = 0);
public :
void show_all_numbers () const;
void show_last_number () const;
void show_number (ulong n_i);
Fibonacci (uint n_i = 0) { get_number (n_i); }
~Fibonacci () {}
};
// -----------------------
BigInt Fibonacci::get_number (uint n_i)
{
fibs_.reserve(n_i + 1);
const uint cur_size = fibs_.size ();
for (uint i = cur_size; i <= n_i; ++i)
{
switch (i)
{
case 0 :
fibs_.push_back (BigInt(0));
break;
case 1 :
if (fibs_.empty ()) fibs_.push_back (BigInt (0));
fibs_.push_back(BigInt (1));
break;
default :
fibs_.push_back (BigInt (get_number (i - 2), get_number (i - 1)));
break;
}
}
ASSERT (n_i < fibs_.size());
return fibs_ [n_i];
}
// -----------------------
void Fibonacci::show_all_numbers () const
{
ostringstream oss;
for (uint i = 0; i < fibs_.size (); ++i)
{
oss << "Fib [" << i << "] = " << fibs_ [i] << "\n";
} cout << oss.str();
}
// -----------------------
void Fibonacci::show_last_number () const
{
ostringstream oss;
oss << "Fib [" << (fibs_.size() - 1) << "] = " << fibs_.back() << "\n";
cout << oss.str();
}
// -----------------------
void Fibonacci::show_number (ulong n_i)
{
ostringstream oss;
if (!(n_i < fibs_.size())) get_number (n_i);
oss << "Fib [" << n_i << "] = " << fibs_[n_i] << "\n";
cout << oss.str();
}
// -------------------
ulong BigInt::head_s (0);
// ==============================
#define ALL_FIBS "all"
#define TH_FIB "th"
#define SOME_FIBS "some"
#define RAND_FIBS "rand"
#define MAX_RAND_FIB 25000
#define SETW1 4
// ---------------------
void usage (char **argv)
{
argv[0] = "bigfib";
cerr << "USAGE : "
<< endl
<< " "
<< argv[0]
<< " "
<< setw (SETW1)
<< std::left
<< ALL_FIBS
<< " <N> ---> Fibonacci [0 - N]"
<< endl
<< " "
<< argv[0]
<< " "
<< std::left
<< setw (SETW1)
<< TH_FIB
<< " <N> ---> Fibonacci [N]"
<< endl
<< " "
<< argv[0]
<< " "
<< std::left
<< setw (SETW1)
<< SOME_FIBS
<< " <N1> [<N2> ...] ---> Fibonacci [N1], Fibonacci [N2], ..."
<< endl
<< " "
<< argv[0]
<< " "
<< std::left
<< setw (SETW1)
<< RAND_FIBS
<< " <K> [<M>] ---> K random Fibonacci numbers ( < M; Default = "
<< MAX_RAND_FIB
<< " )"
<< endl;
}
// ---------------------
string check (int argc, char **argv)
{
if (argc < 3) return string();
const string str (argv[1]);
if (
(str == ALL_FIBS)
||
(str == TH_FIB)
||
(str == SOME_FIBS)
||
(str == RAND_FIBS)
)
{
return str;
}
return string();
}
// ---------------------
int main (int argc, char **argv)
{
string option (check (argc, argv));
uint N;
if (option.empty()) {
// usage (argv);
// return 1;
option = TH_FIB;
#ifdef SMALL_PROBLEM_SIZE
N = 15000;
#else
N = 50000;
#endif
} else {
N = atoi (argv[2]);
}
if (option == ALL_FIBS)
{
Fibonacci fib(N);
fib.show_all_numbers();
}
if (option == TH_FIB)
{
Fibonacci fib(N);
fib.show_last_number();
}
if (option == SOME_FIBS)
{
Fibonacci fib;
for (int i = 2; i < argc; i++) fib.show_number (atoi(argv[i]));
}
if (option == RAND_FIBS)
{
const int max_rand_fib = (argc == 3) ? MAX_RAND_FIB : atoi (argv[3]);
Fibonacci fib;
for (uint i = 0; i < N; i++) fib.show_number (rand()%max_rand_fib);
}
return 0;
}