// ########################################### // [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 #include #include #include #include #include #include #include #include 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 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 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 << " ---> Fibonacci [0 - N]" << endl << " " << argv[0] << " " << std::left << setw (SETW1) << TH_FIB << " ---> Fibonacci [N]" << endl << " " << argv[0] << " " << std::left << setw (SETW1) << SOME_FIBS << " [ ...] ---> Fibonacci [N1], Fibonacci [N2], ..." << endl << " " << argv[0] << " " << std::left << setw (SETW1) << RAND_FIBS << " [] ---> 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; }