Free Web Hosting Provider - Web Hosting - E-commerce - High Speed Internet - Free Web Page
Search the Web


// ############################################
// =============================
//  Very Large Fibonacci Numbers
// =============================
//
//  AUTHOR : Alex Vinokur
//           alexvn@go.to, alexv@hitechclub.com
//           http://up.to/alexvn
//
//  2002-12-05
//
// #############################################


// ------------
// FILE : fib.h
// ------------

#ifndef __fib_H
#define __fib_H             

// ###===###===###===###===###===###===###===###===###===###

#include <assert.h>
#include <string>
#include <sstream>
#include <vector>
#include <iostream>
#include <iomanip>
#include <bits/ios_base.h>
using namespace std;

// #######################################################
// ##### PART#1 : TYPEDEFs & DEFINES & CONSTANTS #########
// #######################################################

#define MAX_VALUE(x,y)          ((x) > (y) ? (x) : (y))
#define ASSERT(x)               assert (x)
#define INFO_MESSAGE

typedef unsigned int uint;
typedef unsigned long ulong;

const ulong  Max_Unit_Value_CNS      = (ULONG_MAX >> 2);
const uint  INFO_period_CNS         = 10000;
static const string     UNITS_Delimeter_CNS     = "";


// #######################################################
// ##### PART#2 : DECLARATIONS ###########################
// #######################################################

template <uint EXPO, uint UNIT_BASE>
class ClassDesirableLongInt;

template <uint EXPO, uint UNIT_BASE>
ClassDesirableLongInt<EXPO, UNIT_BASE> operator+ (
   const ClassDesirableLongInt<EXPO, UNIT_BASE>&left_i,
   const ClassDesirableLongInt<EXPO, UNIT_BASE>&right_i
   );



// #######################################################
// ##### PART#3 : The ClassDesirableLongInt class ########
// #######################################################

// #############################
template <uint EXPO, uint UNIT_BASE>
class ClassDesirableLongInt
{

template <uint E1, uint U1>
friend ClassDesirableLongInt<E1, U1> operator+ (
   const ClassDesirableLongInt<E1, U1>& left_i,
   const ClassDesirableLongInt<E1, U1>& right_i
   );

  private :
    ulong               full_base_;
    vector <ulong>      vector_unit_;

  public :

    ClassDesirableLongInt ();
    ClassDesirableLongInt (ulong unit_value_i);
    ClassDesirableLongInt (
   const ClassDesirableLongInt<EXPO, UNIT_BASE>& left_i,
   const ClassDesirableLongInt<EXPO, UNIT_BASE>& right_i
   );
    ~ClassDesirableLongInt () {}

    void set_full_base ();
    string getValueComment (ios_base& show_base_i (ios_base&)) const;
    string getStrValue (ios_base& show_base_i (ios_base&)) const;
    string getAllInfo (ios_base& show_base_i (ios_base&)) const;
    uint getSize (ios_base& show_base_i (ios_base&)) const;
    static uint getSize_S (const string& strValue_i);
    uint getTotalUnits () const {return vector_unit_.size ();}
};


// =====================
template <uint EXPO, uint UNIT_BASE>
ClassDesirableLongInt<EXPO, UNIT_BASE> operator+ (
   const ClassDesirableLongInt<EXPO, UNIT_BASE>&left_i,
   const ClassDesirableLongInt<EXPO, UNIT_BASE>&right_i
   )
{
ClassDesirableLongInt<EXPO, UNIT_BASE> ret_ClassDesirableLongInt_Value;

const ulong max_size_CNS = MAX_VALUE (
   left_i.vector_unit_.size (),
   right_i.vector_unit_.size ()
   );
ulong cur_big_value;
ulong head = 0;

  for (ulong theIndex = 0; theIndex < max_size_CNS; theIndex++)
  {
    ASSERT (head < Max_Unit_Value_CNS);

    cur_big_value =
      (
        (theIndex < left_i.vector_unit_.size ()) ?
        left_i.vector_unit_ [theIndex] : 0
      )
      +
      (
        (theIndex < right_i.vector_unit_.size ()) ?
        right_i.vector_unit_ [theIndex] : 0
      )
      +
      head;

   // ------------------------

ret_ClassDesirableLongInt_Value.vector_unit_.push_back(cur_big_value%(left_i.full_base_));

   ASSERT (
   ret_ClassDesirableLongInt_Value.vector_unit_
      [ret_ClassDesirableLongInt_Value.vector_unit_.size () - 1]
   <
   left_i.full_base_
   );

   // ------------------------
   head = cur_big_value/(left_i.full_base_);

 } // for (ulong theIndex = 0;


  ASSERT (ret_ClassDesirableLongInt_Value.vector_unit_.size () == max_size_CNS);

  if (head)
  {
    ret_ClassDesirableLongInt_Value.vector_unit_.push_back (head);
  }


  return ret_ClassDesirableLongInt_Value;

} // ClassDesirableLongInt<EXPO, UNIT_BASE> operator+

// =====================
// Constructor-0
template <uint EXPO, uint UNIT_BASE>
ClassDesirableLongInt<EXPO, UNIT_BASE>::ClassDesirableLongInt ()
{
  set_full_base ();
}


// =====================
// Constructor-1
template <uint EXPO, uint UNIT_BASE>
ClassDesirableLongInt<EXPO, UNIT_BASE>::ClassDesirableLongInt (
   ulong unit_value_i
   )
{
  set_full_base ();

  if (!(unit_value_i < full_base_))
  {
    cout << "FATAL ERROR : Number Value = "
         << unit_value_i
         << " (too big)"
         << "; It must be less "
         << full_base_
         << "; "
         << __FILE__
         << ", #"
         << __LINE__
         << endl;

    exit (1);
  }
  ASSERT (unit_value_i < full_base_);
  vector_unit_.push_back (unit_value_i);

}


// =====================
// Constructor-2
template <uint EXPO, uint UNIT_BASE>
ClassDesirableLongInt<EXPO, UNIT_BASE>::ClassDesirableLongInt (
   const ClassDesirableLongInt<EXPO, UNIT_BASE>&left_i,
   const ClassDesirableLongInt<EXPO, UNIT_BASE>&right_i
                                )
{
  set_full_base ();
  (*this) = left_i + right_i;
}


// =====================
template <uint EXPO, uint UNIT_BASE>
string ClassDesirableLongInt<EXPO, UNIT_BASE>::getStrValue (
   ios_base& show_base_i(ios_base&)
   ) const
{
string      ret_Value;
ostringstream  oss;

  ASSERT ((show_base_i == dec) || (show_base_i == hex) || (show_base_i == oct));

  // ------------
  if (!vector_unit_.empty ())
  {
    for (ulong theIndex = (vector_unit_.size () - 1);
        theIndex > 0;
        theIndex--
        )
    {
      oss << show_base_i;
      oss << vector_unit_ [theIndex];
      oss << UNITS_Delimeter_CNS;
      oss << setw (EXPO) << setfill ('0');
    }
    oss << show_base_i;
    oss << vector_unit_ [0];
  }
  else
  {
    oss << "NoValue";
  }

  // ------------
  oss << dec;
  oss << ends;
  ret_Value = oss.str();
  return ret_Value;
}


// =====================
template <uint EXPO, uint UNIT_BASE>
string ClassDesirableLongInt<EXPO, UNIT_BASE>::getAllInfo (
   ios_base& show_base_i (ios_base&)
   ) const
{
string      ret_Value;
ostringstream  oss;
string  stringValue (getStrValue(show_base_i));

  oss << stringValue;
  oss << ";";

  oss << "\t  Size = ";
  oss << getSize_S (stringValue);
  oss << getValueComment (show_base_i);
  oss << ends;

  ret_Value = oss.str();

  return ret_Value;
}


// =====================
template <uint EXPO, uint UNIT_BASE>
uint ClassDesirableLongInt<EXPO, UNIT_BASE>::getSize (
   ios_base& show_base_i(ios_base&)
   ) const
{
  return getSize_S (getStrValue (show_base_i));
}

// =====================
// static
template <uint EXPO, uint UNIT_BASE>
uint ClassDesirableLongInt<EXPO, UNIT_BASE>::getSize_S (
   const string& strValue_i
   )
{
int   counter = 0;
string::size_type ret_index;
string   cur_substr = strValue_i;

  if (!UNITS_Delimeter_CNS.empty ())
  {
    while (!((ret_index = cur_substr.find (UNITS_Delimeter_CNS)) == string::npos))
     {
       counter++;
       cur_substr = cur_substr.substr (ret_index + 1);
     } // while
  }

  return (strValue_i.size () - counter*UNITS_Delimeter_CNS.size ());
}

// =====================
template <uint EXPO, uint UNIT_BASE>
string ClassDesirableLongInt<EXPO, UNIT_BASE>::getValueComment (
   ios_base& show_base_i(ios_base&)
   ) const
{
string ret_Value;

  ASSERT ((show_base_i == dec) || (show_base_i == hex) || (show_base_i == oct));

  ret_Value += " (";

  if (show_base_i == hex) ret_Value += "hex";
  if (show_base_i == oct) ret_Value += "oct";
  if (show_base_i == dec) ret_Value += "dec";

  ret_Value += " digits)";

  return ret_Value;
}




// =====================
template <uint EXPO, uint UNIT_BASE>
void ClassDesirableLongInt<EXPO, UNIT_BASE>::set_full_base ()
{
  ASSERT (EXPO > 1);
  ASSERT ((UNIT_BASE == 8) || (UNIT_BASE == 10) || (UNIT_BASE == 16));

  // ------------------
  full_base_ = 1;
  for (ulong theIndex = 1; theIndex <= EXPO; theIndex++)
  {
    full_base_ *= UNIT_BASE;
    if ((full_base_ >= Max_Unit_Value_CNS) || (full_base_ == 0))
    {
      cout << "FATAL ERROR : EXPO Value = "
           << EXPO
           << " (too big)"
           << "; It must be less "
           << theIndex
           << "  (Note! UNIT_BASE == "
           << UNIT_BASE
           << ")"
           << __FILE__
           << ", #"
           << __LINE__
           << endl;

      exit (1);
    }
  ASSERT (UNIT_BASE * ((full_base_/UNIT_BASE) + 1) < Max_Unit_Value_CNS);
  ASSERT (full_base_ != 0);
  }
}



// #######################################################
// ##### PART#4 : The ClassTemplateFibonacci class #######
// #######################################################

// =====================
template <uint EXPO, uint UNIT_BASE>
class ClassTemplateFibonacci
{
  private :
    vector< ClassDesirableLongInt<EXPO, UNIT_BASE> >     fib_vector_;

  protected :
    ClassTemplateFibonacci (int n_i = 0);

  public :
    string          getAllNumbers (ios_base& show_base_i (ios_base&)) const;
    string          getAllSizes (ios_base& show_base_i (ios_base&)) const;
    virtual ClassDesirableLongInt<EXPO, UNIT_BASE>     getFibNumber(int n_i = 0);

    virtual ~ClassTemplateFibonacci () {}

};

// -----------------------
// Constructor
template <uint EXPO, uint UNIT_BASE>
ClassTemplateFibonacci<EXPO, UNIT_BASE>::ClassTemplateFibonacci (int n_i)
{
  getFibNumber (n_i);
}

// -----------------------
template <uint EXPO, uint UNIT_BASE>
ClassDesirableLongInt<EXPO, UNIT_BASE> ClassTemplateFibonacci<EXPO, UNIT_BASE>::getFibNumber (int n_i)
{
const uint cur_size =   fib_vector_.size ();

  // ------------------

  if (n_i < 0)
  {
    cout << "FATAL ERROR : n = "
         << n_i
         << "; "
         << __FILE__
         << ", #"
         << __LINE__
         << endl;
    exit (1);
  }

  for (uint i = cur_size; i <= n_i; i++)
  {
    switch (i)
    {
      case 0 :
        fib_vector_.push_back (ClassDesirableLongInt<EXPO, UNIT_BASE>(0));
        break;

      case 1 :
        if (fib_vector_.empty ())
        {
          fib_vector_.push_back (ClassDesirableLongInt<EXPO, UNIT_BASE> (0));
        }
        fib_vector_.push_back(ClassDesirableLongInt<EXPO, UNIT_BASE> (1));
        break;

      default :
        fib_vector_.push_back (
      ClassDesirableLongInt<EXPO, UNIT_BASE> (
         getFibNumber (i - 2),
         getFibNumber (i - 1)
         //fib_vector_ [i - 2],
         //fib_vector_ [i - 1]
         )
         );
        break;
    } // switch (n_i)

    // ------------------
#ifdef INFO_MESSAGE
    if ((i%INFO_period_CNS == 0) & (i > 0))
    {
      cerr << "INFO"
           << " ("
           << __FILE__
           << ", #"
           << __LINE__
           << ")"
           << " : "
           << " Fib#"
           << i
           << " computed; Total Units = "
           << fib_vector_ [fib_vector_.size () - 1].getTotalUnits ()
           << endl;
    }
#endif
    // ------------------

  } // for (int i = cur_size; i <= n_i; i++)

  return fib_vector_ [n_i];

} // ulong ClassTemplateFibonacci::getFibNumber (int n_i)


// -----------------------
template <uint EXPO, uint UNIT_BASE>
string ClassTemplateFibonacci<EXPO, UNIT_BASE>::getAllNumbers (
   ios_base& show_base_i (ios_base&)
   ) const
{
string          ret_Value;
ostringstream       oss;

  for (uint i = 0; i < fib_vector_.size (); i++)
  {
    oss << "Fib ["
        << i
        << "] = "
        << fib_vector_ [i].getAllInfo (show_base_i)
        << endl;
  }

  oss << ends;
  ret_Value = oss.str();

  return ret_Value;

} // string ClassTemplateFibonacci::getAllNumbers () const


// -----------------------
template <uint EXPO, uint UNIT_BASE>
string ClassTemplateFibonacci<EXPO, UNIT_BASE>::getAllSizes (
   ios_base& show_base_i (ios_base&)
   ) const
{
string          ret_Value;
ostringstream       oss;

  for (uint i = 0; i < fib_vector_.size (); i++)
  {
    oss << "Fib [" << i << "] : Size is\t "
        << fib_vector_ [i].getSize (show_base_i)
        << fib_vector_ [i].getValueComment (show_base_i)
        << endl;
  }

  oss << ends;
  ret_Value = oss.str();

  return ret_Value;
} // string ClassTemplateFibonacci::getAllSizes () const



// #######################################################
// ##### PART#5 : The ClassTemplateOneFibonacci class ####
// #######################################################

// =====================
template <uint EXPO, uint UNIT_BASE>
class ClassTemplateOneFibonacci : public ClassTemplateFibonacci<EXPO, UNIT_BASE>
{
  private :

  protected :
    ClassTemplateOneFibonacci (int n_i = 0) :
     ClassTemplateFibonacci<EXPO, UNIT_BASE> (n_i) {}

  public :
    ClassDesirableLongInt<EXPO, UNIT_BASE>  getFibNumber (int n_i = 0);
    ~ClassTemplateOneFibonacci () {} };


// -----------------------
template <uint EXPO, uint UNIT_BASE>
ClassDesirableLongInt<EXPO, UNIT_BASE> ClassTemplateOneFibonacci<EXPO,
UNIT_BASE>::getFibNumber (int n_i)
{
vector < ClassDesirableLongInt<EXPO, UNIT_BASE> >  one_vector_;
  one_vector_.push_back (ClassDesirableLongInt<EXPO, UNIT_BASE> (0));
  one_vector_.push_back (ClassDesirableLongInt<EXPO, UNIT_BASE> (1));
  one_vector_.push_back (ClassDesirableLongInt<EXPO, UNIT_BASE> (0));
  // ========================

  if (n_i < 0)
  {
    cout << "FATAL ERROR : n = "
         << n_i
         << "; "
         << __FILE__
         << ", #"
         << __LINE__
         << endl;
    exit (1);
  }

  // ------------------
  for (int theIndex = 0; theIndex < n_i; theIndex++)
  {
    one_vector_.erase (one_vector_.begin ());;
    one_vector_.push_back (one_vector_ [0] + one_vector_ [1]);

#ifdef INFO_MESSAGE
    if ((theIndex%INFO_period_CNS == 0) & (theIndex > 0))
    {
      cerr << "INFO"
           << " ("
           << __FILE__
           << ", #"
           << __LINE__
           << ")"
           << " : "
           << " Fib#"
           << theIndex
           << " computed; Total Units = "
           << one_vector_ [2].getTotalUnits ()
           << endl;
    }
 #endif
  }
  // ------------------

  return one_vector_ [2];

} // ulong ClassTemplateOneFibonacci::getFibNumber (int n_i)


// #######################################################
// ##### PART#6 : The ClassDecUnitFibonacci class ########
// #######################################################

// =====================
template <uint EXPO>
class ClassDecUnitFibonacci : public ClassTemplateFibonacci <EXPO, 10>
{
  public :
    ClassDecUnitFibonacci (int n_i = 0) :
    ClassTemplateFibonacci<EXPO, 10> (n_i) {}
    ~ClassDecUnitFibonacci () {}
};

// ==========================
typedef ClassDecUnitFibonacci<9>      ClassFibonacci;
// ==========================



// #######################################################
// ##### PART#7 : The ClassDecUnitOneFibonacci class #####
// #######################################################

// =====================
template <uint EXPO>
class ClassDecUnitOneFibonacci : public ClassTemplateOneFibonacci <EXPO, 10>
{
  public :
    ClassDecUnitOneFibonacci (int n_i = 0) :
    ClassTemplateOneFibonacci<EXPO, 10> (n_i) {}
    ~ClassDecUnitOneFibonacci () {}
};

// ==========================
typedef ClassDecUnitOneFibonacci<9>   ClassOneFibonacci;
// ==========================



// #######################################################
// ##### PART#8 : The ClassHexUnitFibonacci class ########
// #######################################################

// =====================
template <uint EXPO>
class ClassHexUnitFibonacci : public ClassTemplateFibonacci <EXPO, 16>
{
  public :
    ClassHexUnitFibonacci (int n_i = 0) :
    ClassTemplateFibonacci<EXPO, 16> (n_i) {}
    ~ClassHexUnitFibonacci () {}
};


// #######################################################
// ##### PART#9 : The ClassHexUnitOneFibonacci class #####
// #######################################################

// =====================
template <uint EXPO> class ClassHexUnitOneFibonacci : public ClassTemplateOneFibonacci <EXPO, 16>
{
  public :
   ClassHexUnitOneFibonacci (int n_i = 0) :
   ClassTemplateOneFibonacci<EXPO, 16> (n_i) {}
   ~ClassHexUnitOneFibonacci () {}
};



// #######################################################
// ##### PART#10 : FUNCTIONS #############################
// #######################################################

bool    stringIsDigit (const string& string_i);
bool    stringIsNonDigit (const string& string_i);

void    printAllFib (
                        ulong    n_i,
                        bool     size_only_i = false,
                        const string&  msg_i = string (),
                        ios_base&   show_base_i (ios_base&) = dec
                        );

void    printOneFib (
                        ulong    n_i,
                        const string&   msg_i = string (),
                        ios_base&   show_base_i (ios_base&) = dec
                        );

void    printSomeFib (
                        const vector<ulong>&        vect_i,
                        const string&   msg_i = string (),
                        ios_base&   show_base_i (ios_base&) = dec
                        );

int     mainFib (int argc, char **argv);


// ###===###===###===###===###===###===###===###===###===###
#endif // __fib_H


// ############ END OF FILE ############