Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //Author:
- //user
- //tition @ the forums in www.cplusplus.com
- #include<sstream>
- #include<iostream>
- #include<vector>
- class MathRoutines
- {
- public:
- template <class Element>
- static void RaiseToPower
- (Element& theElement, int thePower, const Element& theRingUnit);
- inline static int Maximum(int a, int b){ if (a>b) return a; else return b; }
- };
- class LargeUI
- { std::vector<unsigned int> theDigits;
- void AddNoFitSize(const LargeUI& x);
- public:
- //The zero element is assumed to have length one array with a zero entry.
- //CarryOverBound is the "base" over which we work.
- //Requirements on the CarryOverBound:
- //1. CarryOverBound*2-1 must fit inside an unsigned (int)
- // on the system
- //2. (CarryOverBound*2)^2-1 must fit inside (long long)
- // on the system.
- static const unsigned int CarryOverBound=1000000000UL;
- void SubtractSmallerPositive(const LargeUI& x);
- inline int size()const{return this->theDigits.size();}
- std::string ElementToStringDecimal()const;
- void MakeOne(){ this->theDigits.resize(1); this->theDigits[0]=1;}
- void MakeZero(){ this->theDigits.resize(1); this->theDigits[0]=0;}
- bool IsGEQ(const LargeUI& x)const;
- static void GetAllPrimesSmallerThanOrEqualToUseEratosthenesSieve
- (unsigned int n, std::vector<unsigned int>& output)
- { std::vector<int> theSieve;
- theSieve.resize(n+1);
- for (unsigned int i=0; i<n+1; i++)
- theSieve[i]=1;
- output.resize(0);
- output.reserve(n/2);
- for (unsigned int i=2; i<=n; i++)
- if (theSieve[i]!=0)
- { output.push_back(i);
- for (unsigned int j=i; j<=n; j+=i)
- theSieve[j]=0;
- }
- }
- inline void operator*=(const LargeUI& right);
- void AssignFactorial(unsigned int x);
- void MultiplyBy(const LargeUI& x, LargeUI& output)const;
- void AddShiftedUIntSmallerThanCarryOverBound(unsigned int x, int shift);
- void AssignShiftedUInt(unsigned int x, int shift);
- inline void operator=(const LargeUI& other) { this->theDigits=other.theDigits; }
- inline void operator+=(const LargeUI& other);
- LargeUI(){ this->theDigits.push_back(0); }
- void FitSize();
- };
- int main()
- { std::cout << "2011 factorial equals ...";
- LargeUI tempInt;
- tempInt.AssignFactorial(2011);
- std::cout << tempInt.ElementToStringDecimal();
- unsigned int x;
- std::cout << "\nNow your turn - enter factorial you want computed \
- (enter large number at your own risk): ";
- std::cin >> x;
- tempInt.AssignFactorial(x);
- std::cout << "\n" << x << " factorial equals: "
- << tempInt.ElementToStringDecimal();
- std::cin >> x;
- return 0;
- }
- void LargeUI::AssignFactorial(unsigned int x)
- { this->MakeOne();
- std::vector<unsigned int> primesBelowX;
- LargeUI::GetAllPrimesSmallerThanOrEqualToUseEratosthenesSieve
- (x, primesBelowX);
- LargeUI tempInt, tempOne;
- tempOne.MakeOne();
- for (unsigned int i=0; i<primesBelowX.size(); i++)
- { unsigned int thePrime=primesBelowX[i];
- unsigned int thePowerOfThePrime=0;
- unsigned int currentPower=thePrime;
- do
- { thePowerOfThePrime+=x/currentPower;
- currentPower*=thePrime;
- }
- while (currentPower<=x);
- tempInt.AssignShiftedUInt(thePrime, 0);
- MathRoutines::RaiseToPower
- (tempInt, thePowerOfThePrime, tempOne);
- *this*=tempInt;
- }
- }
- template <class Element>
- void MathRoutines::RaiseToPower
- (Element& theElement, int thePower, const Element& theOne)
- { if (thePower<0)
- return;
- if (thePower==1)
- return;
- if (thePower==0)
- { theElement=theOne;
- return;
- }
- Element Result;
- Result=theOne;
- if (thePower<4)
- { for (int i=0; i<thePower; i++)
- Result.operator*=(theElement);
- theElement=Result;
- return;
- }
- std::vector<Element> containerList;
- int log2RoundedDown=0;
- int HighestPowerLowerThanOrEqualToThePower=1;
- for (; HighestPowerLowerThanOrEqualToThePower<=thePower;
- HighestPowerLowerThanOrEqualToThePower*=2)
- log2RoundedDown++;
- HighestPowerLowerThanOrEqualToThePower/=2;
- log2RoundedDown--;
- containerList.reserve(log2RoundedDown);
- Result=theElement;
- containerList.push_back(Result);
- for (int i=1; i<=log2RoundedDown; i++)
- { Result.operator*=(Result);
- containerList.push_back(Result);
- }
- thePower-=HighestPowerLowerThanOrEqualToThePower;
- HighestPowerLowerThanOrEqualToThePower/=2;
- int currentIndex=containerList.size()-2;
- for (; thePower>0; )
- { if (thePower>=HighestPowerLowerThanOrEqualToThePower)
- { Result.operator*=(containerList[currentIndex]);
- thePower-=HighestPowerLowerThanOrEqualToThePower;
- }
- currentIndex--;
- HighestPowerLowerThanOrEqualToThePower/=2;
- }
- theElement=Result;
- }
- inline void LargeUI::AddShiftedUIntSmallerThanCarryOverBound
- (unsigned int x, int shift)
- {// assert(x<LargeUI::CarryOverBound);
- while (x>0)
- { if (shift>=this->size())
- { int oldsize=this->size();
- this->theDigits.resize(shift+1);
- for (int i=oldsize; i<this->size(); i++)
- this->theDigits[i]=0;
- }
- this->theDigits[shift]+=x;
- if (this->theDigits[shift]>=LargeUI::CarryOverBound)
- { this->theDigits[shift]-=LargeUI::CarryOverBound;
- x=1;
- shift++;
- } else
- x=0;
- }
- // this->FitSize();
- }
- inline void LargeUI::AssignShiftedUInt(unsigned int x, int shift)
- { if (x==0)
- { this->MakeZero();
- return;
- }
- this->theDigits.resize(shift+1);
- for (int i=0; i<shift; i++)
- this->theDigits[i]=0;
- unsigned int tempX= x%LargeUI::CarryOverBound;
- this->theDigits[shift]=tempX;
- x= x/LargeUI::CarryOverBound;
- while (x!=0)
- { tempX= x%LargeUI::CarryOverBound;
- this->theDigits.push_back(tempX);
- x= x/LargeUI::CarryOverBound;
- }
- }
- inline void LargeUI::AddNoFitSize(const LargeUI& x)
- { int oldsize= this->size();
- this->theDigits.resize(MathRoutines::Maximum(this->size(), x.size())+1);
- for (int i=oldsize; i<this->size(); i++)
- this->theDigits[i]=0;
- unsigned int CarryOver=0;
- for(int i=0; i<x.size(); i++)
- { this->theDigits[i]+=x.theDigits[i]+CarryOver;
- if (this->theDigits[i]>=LargeUI::CarryOverBound)
- { this->theDigits[i]-=LargeUI::CarryOverBound;
- CarryOver=1;
- }
- else
- CarryOver=0;
- }
- if (CarryOver!=0)
- for(int i=x.size(); i<this->size(); i++)
- { this->theDigits[i]+=1;
- if (this->theDigits[i]>=LargeUI::CarryOverBound)
- this->theDigits[i]-=LargeUI::CarryOverBound;
- else
- break;
- }
- }
- void LargeUI::operator+=(const LargeUI& x)
- { this->AddNoFitSize(x);
- this->FitSize();
- }
- void LargeUI::SubtractSmallerPositive(const LargeUI& x)
- { unsigned int CarryOver=0;
- // assert(this->IsGEQ(x));
- for (int i=0; i<x.size(); i++)
- if (this->theDigits[i]<x.theDigits[i]+CarryOver)
- { this->theDigits[i]+=LargeUI::CarryOverBound;
- this->theDigits[i]-=(x.theDigits[i]+CarryOver);
- CarryOver=1;
- }
- else
- { this->theDigits[i]-=(x.theDigits[i]+CarryOver);
- CarryOver=0;
- }
- if (CarryOver!=0)
- { for (int i=x.size(); i<this->size(); i++)
- if (this->theDigits[i]>0)
- { this->theDigits[i]--;
- break;
- }
- else
- this->theDigits[i]=LargeUI::CarryOverBound-1;
- }
- this->FitSize();
- // assert(this->CheckForConsistensy());
- }
- void LargeUI::MultiplyBy(const LargeUI& x, LargeUI& output)const
- {// assert(this!=&output && &x!=&output);
- output.theDigits.resize(x.size()+output.size());
- for(int i=0; i<output.size(); i++)
- output.theDigits[i]=0;
- for (int i=0; i<this->size(); i++)
- for(int j=0; j<x.size(); j++)
- { unsigned long long tempLong= this->theDigits[i];
- unsigned long long tempLong2= x.theDigits[j];
- tempLong= tempLong*tempLong2;
- unsigned long long lowPart= tempLong%LargeUI::CarryOverBound;
- unsigned long long highPart= tempLong/LargeUI::CarryOverBound;
- output.AddShiftedUIntSmallerThanCarryOverBound((unsigned int) lowPart, i+j);
- output.AddShiftedUIntSmallerThanCarryOverBound((unsigned int) highPart, i+j+1);
- }
- output.FitSize();
- // assert(this->CheckForConsistensy());
- }
- void LargeUI::FitSize()
- { int newSize=this->size();
- for (int i=this->size()-1; i>=1; i--)
- if (this->theDigits[i]==0)
- newSize--;
- else
- break;
- this->theDigits.resize(newSize);
- // assert(this->CheckForConsistensy());
- }
- void LargeUI::operator*=(const LargeUI& x)
- { LargeUI tempInt;
- this->MultiplyBy(x, tempInt);
- this->operator=(tempInt);
- // assert(this->CheckForConsistensy());
- }
- bool LargeUI::IsGEQ(const LargeUI& x)const
- { if (this->size()>x.size())
- return true;
- if (this->size()<x.size())
- return false;
- for (int i=this->size()-1; i>=0; i--)
- { if (x.theDigits[i]>this->theDigits[i])
- return false;
- if (x.theDigits[i]<this->theDigits[i])
- return true;
- }
- return true;
- }
- std::string LargeUI::ElementToStringDecimal()const
- { std::stringstream out;
- if (this->CarryOverBound!=1000000000UL)
- return "When CarryOverBound is not 1000000000 this method is not implemented";
- std::string tempS;
- out << (this->theDigits[this->size()-1]);
- for (int i=this->size()-2; i>=0; i--)
- { std::stringstream tempStream;
- tempStream << this->theDigits[i];
- tempS=tempStream.str();
- int numZeroesToPad=9-tempS.length();
- for (int j=0; j<numZeroesToPad; j++)
- out << "0";
- out << tempS;
- }
- return out.str();
- }
Add Comment
Please, Sign In to add comment