tition

c++ factorial computation

Aug 19th, 2011
2,047
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.29 KB | None | 0 0
  1. //Author:
  2. //user
  3. //tition @ the forums in www.cplusplus.com
  4. #include<sstream>
  5. #include<iostream>
  6. #include<vector>
  7.  
  8. class MathRoutines
  9. {
  10. public:
  11.   template <class Element>
  12.   static void RaiseToPower
  13.   (Element& theElement, int thePower, const Element& theRingUnit);
  14.   inline static int Maximum(int a, int b){  if (a>b) return a; else return b; }
  15. };
  16.  
  17. class LargeUI
  18. { std::vector<unsigned int> theDigits;
  19.   void AddNoFitSize(const LargeUI& x);
  20. public:
  21.   //The zero element is assumed to have length one array with a zero entry.
  22.   //CarryOverBound is the "base" over which we work.
  23.   //Requirements on the CarryOverBound:
  24.   //1.  CarryOverBound*2-1 must fit inside an unsigned (int)
  25.   //    on the system
  26.   //2. (CarryOverBound*2)^2-1 must fit inside (long long)
  27.   //    on the system.
  28.   static const unsigned int CarryOverBound=1000000000UL;
  29.   void SubtractSmallerPositive(const LargeUI& x);
  30.   inline int size()const{return this->theDigits.size();}
  31.   std::string ElementToStringDecimal()const;
  32.   void MakeOne(){ this->theDigits.resize(1);  this->theDigits[0]=1;}
  33.   void MakeZero(){ this->theDigits.resize(1); this->theDigits[0]=0;}
  34.   bool IsGEQ(const LargeUI& x)const;
  35.   static void GetAllPrimesSmallerThanOrEqualToUseEratosthenesSieve
  36.   (unsigned int n, std::vector<unsigned int>& output)
  37.   { std::vector<int> theSieve;
  38.     theSieve.resize(n+1);
  39.     for (unsigned int i=0; i<n+1; i++)
  40.       theSieve[i]=1;
  41.     output.resize(0);
  42.     output.reserve(n/2);
  43.     for (unsigned int i=2; i<=n; i++)
  44.       if (theSieve[i]!=0)
  45.       { output.push_back(i);
  46.         for (unsigned int j=i; j<=n; j+=i)
  47.           theSieve[j]=0;
  48.       }
  49.   }
  50.   inline void operator*=(const LargeUI& right);
  51.   void AssignFactorial(unsigned int x);
  52.   void MultiplyBy(const LargeUI& x, LargeUI& output)const;
  53.   void AddShiftedUIntSmallerThanCarryOverBound(unsigned int x, int shift);
  54.   void AssignShiftedUInt(unsigned int x, int shift);
  55.   inline void operator=(const LargeUI& other)  { this->theDigits=other.theDigits; }
  56.   inline void operator+=(const LargeUI& other);
  57.   LargeUI(){ this->theDigits.push_back(0); }
  58.   void FitSize();
  59. };
  60.  
  61. int main()
  62. { std::cout << "2011 factorial equals ...";
  63.   LargeUI tempInt;
  64.   tempInt.AssignFactorial(2011);
  65.   std::cout << tempInt.ElementToStringDecimal();
  66.   unsigned int x;
  67.   std::cout << "\nNow your turn - enter factorial you want computed \
  68.  (enter large number at your own risk): ";
  69.   std::cin >> x;
  70.   tempInt.AssignFactorial(x);
  71.   std::cout << "\n" << x << " factorial equals: "
  72.   << tempInt.ElementToStringDecimal();
  73.   std::cin >> x;
  74.   return 0;
  75. }
  76.  
  77. void LargeUI::AssignFactorial(unsigned int x)
  78. { this->MakeOne();
  79.   std::vector<unsigned int> primesBelowX;
  80.   LargeUI::GetAllPrimesSmallerThanOrEqualToUseEratosthenesSieve
  81.   (x, primesBelowX);
  82.   LargeUI tempInt, tempOne;
  83.   tempOne.MakeOne();
  84.   for (unsigned int i=0; i<primesBelowX.size(); i++)
  85.   { unsigned int thePrime=primesBelowX[i];
  86.     unsigned int thePowerOfThePrime=0;
  87.     unsigned int currentPower=thePrime;
  88.     do
  89.     { thePowerOfThePrime+=x/currentPower;
  90.       currentPower*=thePrime;
  91.     }
  92.     while (currentPower<=x);
  93.     tempInt.AssignShiftedUInt(thePrime, 0);
  94.     MathRoutines::RaiseToPower
  95.     (tempInt, thePowerOfThePrime, tempOne);
  96.     *this*=tempInt;
  97.   }
  98. }
  99.  
  100. template <class Element>
  101. void MathRoutines::RaiseToPower
  102. (Element& theElement, int thePower, const Element& theOne)
  103. { if (thePower<0)
  104.     return;
  105.   if (thePower==1)
  106.     return;
  107.   if (thePower==0)
  108.   { theElement=theOne;
  109.     return;
  110.   }
  111.   Element Result;
  112.   Result=theOne;
  113.   if (thePower<4)
  114.   { for (int i=0; i<thePower; i++)
  115.       Result.operator*=(theElement);
  116.     theElement=Result;
  117.     return;
  118.   }
  119.   std::vector<Element> containerList;
  120.   int log2RoundedDown=0;
  121.   int HighestPowerLowerThanOrEqualToThePower=1;
  122.   for (; HighestPowerLowerThanOrEqualToThePower<=thePower;
  123.             HighestPowerLowerThanOrEqualToThePower*=2)
  124.     log2RoundedDown++;
  125.   HighestPowerLowerThanOrEqualToThePower/=2;
  126.   log2RoundedDown--;
  127.   containerList.reserve(log2RoundedDown);
  128.   Result=theElement;
  129.   containerList.push_back(Result);
  130.   for (int i=1; i<=log2RoundedDown; i++)
  131.   { Result.operator*=(Result);
  132.     containerList.push_back(Result);
  133.   }
  134.   thePower-=HighestPowerLowerThanOrEqualToThePower;
  135.   HighestPowerLowerThanOrEqualToThePower/=2;
  136.   int currentIndex=containerList.size()-2;
  137.   for (; thePower>0; )
  138.   { if (thePower>=HighestPowerLowerThanOrEqualToThePower)
  139.     { Result.operator*=(containerList[currentIndex]);
  140.       thePower-=HighestPowerLowerThanOrEqualToThePower;
  141.     }
  142.     currentIndex--;
  143.     HighestPowerLowerThanOrEqualToThePower/=2;
  144.   }
  145.   theElement=Result;
  146. }
  147.  
  148. inline void LargeUI::AddShiftedUIntSmallerThanCarryOverBound
  149. (unsigned int x, int shift)
  150. {// assert(x<LargeUI::CarryOverBound);
  151.   while (x>0)
  152.   { if (shift>=this->size())
  153.     { int oldsize=this->size();
  154.       this->theDigits.resize(shift+1);
  155.       for (int i=oldsize; i<this->size(); i++)
  156.         this->theDigits[i]=0;
  157.     }
  158.     this->theDigits[shift]+=x;
  159.     if (this->theDigits[shift]>=LargeUI::CarryOverBound)
  160.     { this->theDigits[shift]-=LargeUI::CarryOverBound;
  161.       x=1;
  162.       shift++;
  163.     } else
  164.       x=0;
  165.   }
  166. //  this->FitSize();
  167. }
  168.  
  169. inline void LargeUI::AssignShiftedUInt(unsigned int x, int shift)
  170. { if (x==0)
  171.   { this->MakeZero();
  172.     return;
  173.   }
  174.   this->theDigits.resize(shift+1);
  175.   for (int i=0; i<shift; i++)
  176.     this->theDigits[i]=0;
  177.   unsigned int tempX= x%LargeUI::CarryOverBound;
  178.   this->theDigits[shift]=tempX;
  179.   x= x/LargeUI::CarryOverBound;
  180.   while (x!=0)
  181.   { tempX= x%LargeUI::CarryOverBound;
  182.     this->theDigits.push_back(tempX);
  183.     x= x/LargeUI::CarryOverBound;
  184.   }
  185. }
  186.  
  187. inline void LargeUI::AddNoFitSize(const LargeUI& x)
  188. { int oldsize= this->size();
  189.   this->theDigits.resize(MathRoutines::Maximum(this->size(), x.size())+1);
  190.   for (int i=oldsize; i<this->size(); i++)
  191.     this->theDigits[i]=0;
  192.   unsigned int CarryOver=0;
  193.   for(int i=0; i<x.size(); i++)
  194.   { this->theDigits[i]+=x.theDigits[i]+CarryOver;
  195.     if (this->theDigits[i]>=LargeUI::CarryOverBound)
  196.     { this->theDigits[i]-=LargeUI::CarryOverBound;
  197.       CarryOver=1;
  198.     }
  199.     else
  200.       CarryOver=0;
  201.   }
  202.   if (CarryOver!=0)
  203.     for(int i=x.size(); i<this->size(); i++)
  204.     { this->theDigits[i]+=1;
  205.       if (this->theDigits[i]>=LargeUI::CarryOverBound)
  206.         this->theDigits[i]-=LargeUI::CarryOverBound;
  207.       else
  208.         break;
  209.     }
  210. }
  211.  
  212. void LargeUI::operator+=(const LargeUI& x)
  213. { this->AddNoFitSize(x);
  214.   this->FitSize();
  215. }
  216.  
  217. void LargeUI::SubtractSmallerPositive(const LargeUI& x)
  218. { unsigned int CarryOver=0;
  219. //  assert(this->IsGEQ(x));
  220.   for (int i=0; i<x.size(); i++)
  221.     if (this->theDigits[i]<x.theDigits[i]+CarryOver)
  222.     { this->theDigits[i]+=LargeUI::CarryOverBound;
  223.       this->theDigits[i]-=(x.theDigits[i]+CarryOver);
  224.       CarryOver=1;
  225.     }
  226.     else
  227.     { this->theDigits[i]-=(x.theDigits[i]+CarryOver);
  228.       CarryOver=0;
  229.     }
  230.   if (CarryOver!=0)
  231.   { for (int i=x.size(); i<this->size(); i++)
  232.       if (this->theDigits[i]>0)
  233.       { this->theDigits[i]--;
  234.         break;
  235.       }
  236.       else
  237.         this->theDigits[i]=LargeUI::CarryOverBound-1;
  238.   }
  239.   this->FitSize();
  240. //  assert(this->CheckForConsistensy());
  241. }
  242.  
  243. void LargeUI::MultiplyBy(const LargeUI& x, LargeUI& output)const
  244. {// assert(this!=&output && &x!=&output);
  245.   output.theDigits.resize(x.size()+output.size());
  246.   for(int i=0; i<output.size(); i++)
  247.     output.theDigits[i]=0;
  248.   for (int i=0; i<this->size(); i++)
  249.     for(int j=0; j<x.size(); j++)
  250.     { unsigned long long tempLong= this->theDigits[i];
  251.       unsigned long long tempLong2= x.theDigits[j];
  252.       tempLong= tempLong*tempLong2;
  253.       unsigned long long lowPart= tempLong%LargeUI::CarryOverBound;
  254.       unsigned long long highPart= tempLong/LargeUI::CarryOverBound;
  255.       output.AddShiftedUIntSmallerThanCarryOverBound((unsigned int) lowPart, i+j);
  256.       output.AddShiftedUIntSmallerThanCarryOverBound((unsigned int) highPart, i+j+1);
  257.     }
  258.   output.FitSize();
  259. //  assert(this->CheckForConsistensy());
  260. }
  261.  
  262. void LargeUI::FitSize()
  263. { int newSize=this->size();
  264.   for (int i=this->size()-1; i>=1; i--)
  265.     if (this->theDigits[i]==0)
  266.       newSize--;
  267.     else
  268.       break;
  269.   this->theDigits.resize(newSize);
  270. //  assert(this->CheckForConsistensy());
  271. }
  272.  
  273. void LargeUI::operator*=(const LargeUI& x)
  274. { LargeUI tempInt;
  275.   this->MultiplyBy(x, tempInt);
  276.   this->operator=(tempInt);
  277. //  assert(this->CheckForConsistensy());
  278. }
  279.  
  280. bool LargeUI::IsGEQ(const LargeUI& x)const
  281. { if (this->size()>x.size())
  282.     return true;
  283.   if (this->size()<x.size())
  284.     return false;
  285.   for (int i=this->size()-1; i>=0; i--)
  286.   { if (x.theDigits[i]>this->theDigits[i])
  287.       return false;
  288.     if (x.theDigits[i]<this->theDigits[i])
  289.       return true;
  290.   }
  291.   return true;
  292. }
  293.  
  294. std::string LargeUI::ElementToStringDecimal()const
  295. { std::stringstream out;
  296.   if (this->CarryOverBound!=1000000000UL)
  297.     return "When CarryOverBound is not 1000000000 this method is not implemented";
  298.   std::string tempS;
  299.   out << (this->theDigits[this->size()-1]);
  300.   for (int i=this->size()-2; i>=0; i--)
  301.   { std::stringstream tempStream;
  302.     tempStream << this->theDigits[i];
  303.     tempS=tempStream.str();
  304.     int numZeroesToPad=9-tempS.length();
  305.     for (int j=0; j<numZeroesToPad; j++)
  306.       out << "0";
  307.     out << tempS;
  308.   }
  309.   return out.str();
  310. }
Add Comment
Please, Sign In to add comment