home *** CD-ROM | disk | FTP | other *** search
- //***************************************************************************
- // OATH :: Object-oriented Abstract Type Hierarchy
- //***************************************************************************
- //
- // Copyright (C) 1991 Texas Instruments Incorporated
- // Permission is granted to any individual or institution
- // to use, copy, modify, and distribute this software,
- // provided that this complete copyright and permission notice
- // is maintained, intact, in all copies and supporting documentation.
- //
- // Texas Instruments Incorporated provides this software "as is"
- // without express or implied warranty.
- //
- //***************************************************************************
- // bigInteger (bigIntegerA, bigIntegerG)
- //
- // History:
- // 08/91 Brian M Kennedy signMagnitudeP; functionality refined
- // 07/91 Brian M Kennedy import, export, typeRegister
- // 06/91 Brian M Kennedy New macros & format; remove printDiagnostic
- // 02/91 Brian M Kennedy Original
- //
- //***************************************************************************
-
- #include "copyright.h"
-
- #include <oath/bigInteger.h>
-
- #include <ctype.h>
-
- #include <limits.h>
-
- #include <iostream.h>
-
- /////////////////////////////////////////////////////////////////////////////
- // unsigned long manipulations
-
- #define FULL 32 /* (CHAR_BIT * sizeof(unsigned long)) */
-
- #define HALF 16 /* (FULL >> 1) */
-
- #define LOWER (~0UL >> HALF)
-
- #define LO(Arg) ((Arg) & LOWER)
-
- #define HI(Arg) ((Arg) >> HALF)
-
- #define UP(Arg) ((Arg) << HALF)
-
- static unsigned int // returns bit number 31=MSB, 0=LSB of MS1
- log2 (unsigned long UL)
- {assumed(UL, "log2 not valid on zero");
- unsigned int UI = 0;
- unsigned long UM = HI(UL);
- if(UM)
- {UL = UM;
- UI += HALF;
- }
- while(UL)
- {UL >>= 1;
- ++UI;
- }
- return UI - 1;
- }
-
-
- /////////////////////////////////////////////////////////////////////////////
- // common call sequences
-
- #define SM_CALL(Arg, Fn) \
- if(Arg->isImplementedAs(Type)) \
- Fn(((bigIntegerG*)Arg)->SAM); \
- else if(Arg->isType(integerG::Type)) \
- Fn(((integerG*)Arg)->smMantissa()); \
- else if(Arg->isType(realG::Type)) \
- {integerA Temp = ((realG*)Arg)->makeTruncate(1); \
- Fn(Temp.guts()->smMantissa()); \
- } \
- else if(Arg->hasZeroImag()) \
- {integerA Temp = Arg->makeReal(1).makeTruncate(1); \
- Fn(Temp.guts()->smMantissa()); \
- } \
- else \
- {ensure(FALSE, "throw offRealAxis::rangeViolation");} \
-
-
- /////////////////////////////////////////////////////////////////////////////
- // bigInteger Outlines
-
- OUTLINES(bigInteger, integer)
-
- // Static Data Members //////////
-
- unsigned long bigIntegerG::ZeroSAMMagnitude; // default init to 0
-
- signMagnitudeP bigIntegerG::ZeroSAM (3, &bigIntegerG::ZeroSAMMagnitude);
-
- // Constructors //////////
-
- bigIntegerG::
- bigIntegerG (const char* S, int IsConst)
- :integerG(IsConst), MaxSize(1), SAM(1, 1, new unsigned long [1])
- {SAM.magnitude(0) = 0;
- while(*S)
- {if(isdigit(*S))
- {smMul10();
- smIncMag(*S - '0');
- }
- else if (*S == '-')
- neg();
- ++S;
- }
- }
-
- bigIntegerG::
- bigIntegerG (const bigIntegerG* I, int IsConst)
- :integerG(IsConst),
- MaxSize((I->SAM.size() > 1) ? I->SAM.size() + 4 : 1),
- SAM(I->SAM.SizeAndSign, new unsigned long [MaxSize])
- {for(unsigned int UI = 0; UI < SAM.size(); ++UI)
- SAM.magnitude(UI) = I->SAM.magnitude(UI);
- }
-
- bigIntegerG::
- bigIntegerG (const signMagnitudeP& ISAM, int IsConst)
- :integerG(IsConst),
- MaxSize((ISAM.size() > 1) ? ISAM.size() + 4 : 1),
- SAM(ISAM.SizeAndSign, new unsigned long [MaxSize])
- {for(unsigned int UI = 0; UI < SAM.size(); ++UI)
- SAM.magnitude(UI) = ISAM.magnitude(UI);
- }
-
-
- // oathCore Operations //////////
-
- void bigIntegerG::
- export (exportP& X) const
- {X.writeType(TypeName);
- X.stream() << SAM.SizeAndSign << (isConst() ? ' ' : '\0');
- for(unsigned int UI = 0; UI < SAM.size(); ++UI)
- X.stream() << SAM.magnitude(UI) << ' ';
- }
-
- objA bigIntegerG::
- import (importP& M)
- {unsigned int SAS;
- M.stream() >> SAS;
- char MakeConst = M.stream().get();
- unsigned int Size = SAS >> 1;
- unsigned int MaxSize = (Size > 1) ? Size + 4 : 1;
- unsigned long * Mag = new unsigned long [MaxSize];
- for(unsigned int UI = 0; UI < Size; ++UI)
- (M.stream() >> Mag[UI]).get();
- return new bigIntegerG (MaxSize, SAS, Mag, MakeConst);
- }
-
-
- // obj Operations //////////
-
- int bigIntegerG::
- isEqual (const objG* O) const
- {return O->isType(integerG::Type) && hasEqual((integerG*)O);}
-
-
- // complex Operations //////////
-
- void bigIntegerG::
- reset ()
- {SAM.size(1);
- SAM.magnitude(0) = 0;
- }
-
- void bigIntegerG::
- reset (const complexG* C)
- {SM_CALL(C, smReset)}
-
- int bigIntegerG::
- hasEqual (const complexG* C) const
- {if(C->isImplementedAs(Type))
- return smHasEqual(((bigIntegerG*)C)->SAM);
- else if(C->isType(integerG::Type))
- return smHasEqual(((integerG*)C)->smMantissa());
- else
- return C->hasEqual(this);
- }
-
- void bigIntegerG::
- increment (const complexG* C)
- {SM_CALL(C, smInc)}
-
- void bigIntegerG::
- decrement (const complexG* C)
- {SM_CALL(C, smDec)}
-
- void bigIntegerG::
- multiply (const complexG* C)
- {if(C->isImplementedAs(Type))
- smMul(((bigIntegerG*)C)->SAM);
- else if(C->isType(integerG::Type))
- smMul(((integerG*)C)->smMantissa());
- else if(hasZero() || C->hasZero())
- reset();
- else if(C->isType(realG::Type))
- {realA R = (realA&)(((realG*)C)->makeCopy(FALSE));
- R.guts()->multiply(this);
- reset(R.guts());
- }
- else if(C->hasZeroImag())
- {realA R = C->makeReal(1);
- R.guts()->multiply(this);
- reset(R.guts());
- }
- else
- {ensure(FALSE, "throw offRealAxis::rangeViolation");}
- }
-
- void bigIntegerG::
- divide (const complexG* C)
- {if(C->isImplementedAs(Type))
- smDiv(((bigIntegerG*)C)->SAM);
- else if(C->isType(integerG::Type))
- smDiv(((integerG*)C)->smMantissa());
- else if(hasZero() || C->hasZero())
- reset();
- else if(C->isType(realG::Type))
- {realA R = (realA&)(((realG*)C)->makeCopy(FALSE));
- R.inv();
- R.guts()->multiply(this);
- reset(R.guts());
- }
- else if(C->hasZeroImag())
- {realA R = C->makeReal(1);
- R.inv();
- R.guts()->multiply(this);
- reset(R.guts());
- }
- else
- {ensure(FALSE, "throw offRealAxis::rangeViolation");}
- }
-
- void bigIntegerG::
- shiftLeft (const integerG* I)
- {smShiftLeft(I->smMantissa());}
-
- void bigIntegerG::
- shiftRight (const integerG* I)
- {smShiftRight(I->smMantissa());}
-
- void bigIntegerG::
- sqr ()
- {signMagnitudeP Copy (SAM);
- Copy.magnitude() = new unsigned long [Copy.size()];
- for(unsigned int UI = 0; UI < Copy.size(); ++UI)
- Copy.magnitude(UI) = SAM.magnitude(UI);
- smMul(Copy);
- delete [] Copy.magnitude();
- }
-
- void bigIntegerG:: // This is just Newton's method, with a
- sqrt () // start value x >>= (log2(x) / 2)
- {if(!SAM.zero())
- {if(!SAM.positive())
- ensure(FALSE, "throw notOnRealAxis::rangeViolation");
- else
- {// Temporaries
- bigIntegerA GuessA = (bigIntegerA&)makeCopy(FALSE);
- bigIntegerG* Guess = GuessA.guts();
- bigIntegerA QuotA = (bigIntegerA&)makeCopy(FALSE);
- bigIntegerG* Quot = QuotA.guts();
- // Initial guess, always high but fairly close
- unsigned int Count = SAM.size() - 1;
- Count *= FULL;
- Count += log2(SAM.magnitude(SAM.size()-1));
- Count >>= 1;
- Guess->smShiftRight(Count);
- // Iterative Convergence
- Quot->divide(Guess);
- while(Quot->hasLess(Guess))
- {Guess->increment(Quot);
- Guess->smShiftRight(1);
- Quot->reset(this);
- Quot->divide(Guess);
- }
- reset(Guess);
- }
- }
- }
-
- void bigIntegerG::
- pow (const integerG* I)
- {if(I->hasZero())
- smReset(1);
- else if(hasZero())
- reset();
- else
- {const signMagnitudeP& SMI = I->smMantissa();
- if(SMI.size() > 1 || !SMI.positive())
- ensure(FALSE, "throw rangeViolation");
- else
- {bigIntegerA I = (bigIntegerA&)makeCopy(TRUE);
- for(unsigned int Count = 0; Count < SMI.magnitude(0); ++Count)
- smMul(I.guts()->SAM);
- }
- }
- }
-
- void bigIntegerG::
- print (ostream& F, char Sep) const
- {int Size = SAM.size() * 10 + 12;
- if(Sep) Size += Size >> 1;
- char * Buffer = new char [Size];
- F << string(Buffer, Size, Sep);
- delete [] Buffer;
- }
-
- // real Operations //////////
-
- int bigIntegerG::
- hasLess (const realG* R) const
- {if(R->isImplementedAs(Type))
- return smHasLess(((bigIntegerG*)R)->SAM);
- else if(R->isType(integerG::Type))
- return smHasLess(((integerG*)R)->smMantissa());
- else
- return R->hasMore(this);
- }
-
- int bigIntegerG::
- hasMore (const realG* R) const
- {if(R->isImplementedAs(Type))
- return smHasMore(((bigIntegerG*)R)->SAM);
- else if(R->isType(integerG::Type))
- return smHasMore(((integerG*)R)->smMantissa());
- else
- return R->hasLess(this);
- }
-
- int bigIntegerG::
- hasDouble () const
- {ensure(FALSE, "Sorry, not implemented!");
- return FALSE;
- }
-
- double bigIntegerG::
- makeDouble () const
- {ensure(FALSE, "Sorry, not implemented!");
- return 0.0;
- }
-
- void bigIntegerG::
- min (const realG* R)
- {if(hasMore(R))
- reset(R);
- }
-
- void bigIntegerG::
- max (const realG* R)
- {if(hasLess(R))
- reset(R);
- }
-
-
- // rational Operations //////////
-
-
- // integer Operations //////////
-
- void bigIntegerG::
- rem (const integerG* I)
- {signMagnitudeP Quotient;
- unsigned int QMaxSize = 0;
- smRemDivMag(I->smMantissa(), Quotient, QMaxSize);
- delete [] Quotient.magnitude();
- }
-
- void bigIntegerG::
- remDivX (const integerG* Divisor, integerG* Quot)
- {bigIntegerA Quotient = bigIntegerA::make();
- smRemDivMag(Divisor->smMantissa(),
- Quotient.guts()->SAM, Quotient.guts()->MaxSize);
- Quot->reset(Quotient.guts());
- }
-
- // Common Factors
-
- // This is based on Knuth, Art of Computer Programming, Vol 2
- // Algorithm B (binary gcd algorithm) discovered by J. Stein.
- // This is an alternative to Euclidean algorithms that uses
- // only subtraction and shifting (no division).
-
- void bigIntegerG::
- gcd (const integerG* I)
- {bigIntegerA One = bigIntegerA::make(1);
- if(hasZero() && I->hasZero())
- reset();
- else
- {abs();
- integerA V = ((integerA&)I->makeCopy(FALSE)).abs();
- unsigned int K = 0;
- while(hasEven() && V.hasEven())
- {++K;
- smShiftRight(1);
- V >>= One;
- }
- integerA T;
- if(!hasEven())
- T = V.makeCopy().neg();
- else
- T = (integerA&)makeCopy(FALSE);
- while(!T.hasZero())
- {while(T.hasEven())
- T >>= One;
- if(T.hasPositive())
- reset(T.guts());
- else
- V.reset(T.neg());
- T.guts()->reset(this);
- T -= V;
- }
- smShiftLeft(K);
- }
- }
-
- void bigIntegerG:: // lcm(I,J) = I * J / gcd(I, J)
- lcm (const integerG* I)
- {if(!hasZero())
- return;
- else if(I->hasZero())
- reset();
- else
- {bigIntegerA GCD = (bigIntegerA&)makeCopy(FALSE);
- GCD.guts()->gcd(I);
- divide(GCD.guts());
- multiply(I);
- abs();
- }
- }
-
-
- // bigInteger Operations //////////
-
-
- void bigIntegerG::
- smGrowMag (unsigned int NewMax)
- {unsigned long * NewMag = new unsigned long [NewMax];
- for(unsigned int UI = 0; UI < SAM.size(); ++UI)
- NewMag[UI] = SAM.magnitude(UI);
- delete [] SAM.magnitude();
- SAM.magnitude() = NewMag;
- MaxSize = NewMax;
- }
-
- void bigIntegerG::
- smReset (long Value)
- {SAM.size(1);
- SAM.positive(Value >= 0);
- SAM.magnitude(0) = (Value >= 0) ? Value : -Value;
- }
-
- void bigIntegerG::
- smReset (const signMagnitudeP& SMI)
- {if(SMI.size() > MaxSize)
- {MaxSize = SMI.size() + 4;
- delete [] SAM.magnitude();
- SAM.magnitude() = new unsigned long [MaxSize];
- }
- SAM.size(SMI.size());
- SAM.positive(SMI.positive());
- for(unsigned int UI = 0; UI < SAM.size(); ++UI)
- SAM.magnitude(UI) = SMI.magnitude(UI);
- }
-
- // Shifts
-
- void bigIntegerG::
- smShiftLeft (unsigned int Count)
- {unsigned int FullCount = Count / FULL;
- unsigned int Shift = Count % FULL;
- if(FullCount)
- {if(SAM.size()+FullCount+1 > MaxSize)
- {MaxSize = SAM.size()+FullCount+4;
- unsigned long* Mag = new unsigned long [MaxSize];
- for(unsigned int UI = 0; UI < FullCount; ++UI)
- Mag[UI] = 0;
- for(UI = 0; UI < SAM.size(); ++UI)
- Mag[UI+FullCount] = SAM.magnitude(UI);
- SAM.size(UI + FullCount);
- delete [] SAM.magnitude();
- SAM.magnitude() = Mag;
- }
- else
- {SAM.size(SAM.size() + FullCount);
- for(unsigned int UI = SAM.size()-1; UI >= FullCount; --UI)
- SAM.magnitude(UI) = SAM.magnitude(UI-FullCount);
- for(; UI < FullCount; --UI)
- SAM.magnitude(UI) = 0;
- }
- }
- if(Shift)
- {unsigned long Carry = 0;
- for(unsigned int UI = 0; UI < SAM.size(); ++UI)
- {unsigned long Next = SAM.magnitude(UI) >> (FULL-Shift);
- SAM.magnitude(UI) <<= Shift;
- SAM.magnitude(UI) |= Carry;
- Carry = Next;
- }
- if(Carry)
- {if(SAM.size() == MaxSize)
- smGrowMag(MaxSize + 4);
- SAM.magnitude(SAM.size()) = Carry;
- SAM.incSize();
- }
- }
- }
-
- void bigIntegerG::
- smShiftLeft (const signMagnitudeP& SMI)
- {if(!SMI.zero() && !SAM.zero())
- {if(!SMI.positive() || SMI.size() != 1 || SMI.magnitude(0) > UINT_MAX)
- {ensure(FALSE, "throw rangeViolation");}
- else
- {smShiftLeft((unsigned int)SMI.magnitude(0));}
- }
- }
-
- void bigIntegerG::
- smShiftRight (unsigned int Count)
- {unsigned int FullCount = Count / FULL;
- if(FullCount >= SAM.size())
- reset();
- else
- {if(FullCount)
- {SAM.size(SAM.size() - FullCount);
- for(unsigned int UI = 0; UI < SAM.size(); ++UI)
- SAM.magnitude(UI) = SAM.magnitude(UI+FullCount);
- }
- unsigned int Shift = Count % FULL;
- if(Shift)
- {unsigned long Carry = 0;
- for(unsigned int UI = SAM.size()-1; UI < SAM.size(); --UI)
- {unsigned long Next = SAM.magnitude(UI) << (FULL-Shift);
- SAM.magnitude(UI) >>= Shift;
- SAM.magnitude(UI) |= Carry;
- Carry = Next;
- }
- if(SAM.size() > 1 && !SAM.magnitude(SAM.size()-1))
- SAM.decSize();
- }
- }
- }
-
- void bigIntegerG::
- smShiftRight (const signMagnitudeP& SMI)
- {if(!SMI.zero() && !SAM.zero())
- {if(!SMI.positive())
- {ensure(FALSE, "throw rangeViolation");}
- else if(SMI.size() > 1 || SMI.magnitude(0) > UINT_MAX)
- {reset();}
- else
- {smShiftRight((unsigned int)SMI.magnitude(0));}
- }
- }
-
- // Comparison
-
- int bigIntegerG::
- smHasEqualMag (const signMagnitudeP& SMI) const
- {if(SAM.size() != SMI.size())
- return FALSE;
- else
- {for(unsigned int UI = 0; UI < SAM.size(); ++UI)
- {if(SAM.magnitude(UI) != SMI.magnitude(UI))
- return FALSE;
- }
- return TRUE;
- }
- }
-
- int bigIntegerG::
- smHasEqual (const signMagnitudeP& SMI) const
- {if(SAM.positive() != SMI.positive())
- {if(SAM.zero() && SMI.zero())
- return TRUE;
- else
- return FALSE;
- }
- else return smHasEqualMag(SMI);
- }
-
- int bigIntegerG::
- smHasLessMag (const signMagnitudeP& SMI) const
- {if(SAM.size() != SMI.size())
- {if(SAM.size() > SMI.size())
- return FALSE;
- else
- return TRUE;
- }
- else
- {for(unsigned int UI = SAM.size()-1; UI < SAM.size(); --UI)
- {if(SAM.magnitude(UI) < SMI.magnitude(UI))
- return TRUE;
- else if(SAM.magnitude(UI) > SMI.magnitude(UI))
- return FALSE;
- }
- return FALSE;
- }
- }
-
- int bigIntegerG::
- smHasMoreMag (const signMagnitudeP& SMI) const
- {if(SAM.size() != SMI.size())
- {if(SAM.size() > SMI.size())
- return TRUE;
- else
- return FALSE;
- }
- else
- {for(unsigned int UI = SAM.size()-1; UI < SAM.size(); --UI)
- {if(SAM.magnitude(UI) > SMI.magnitude(UI))
- return TRUE;
- else if(SAM.magnitude(UI) < SMI.magnitude(UI))
- return FALSE;
- }
- return FALSE;
- }
- }
-
- int bigIntegerG::
- smHasLess (const signMagnitudeP& SMI) const
- {if(SAM.positive() != SMI.positive())
- {if(SAM.positive())
- return FALSE;
- else if(SAM.zero() && SMI.zero())
- return FALSE;
- else
- return TRUE;
- }
- else
- {if(SAM.positive())
- return smHasLessMag(SMI);
- else
- return smHasMoreMag(SMI);
- }
- }
-
- int bigIntegerG::
- smHasMore (const signMagnitudeP& SMI) const
- {if(SAM.positive() != SMI.positive())
- {if(!SAM.positive())
- return FALSE;
- else if(SAM.zero() && SMI.zero())
- return FALSE;
- else
- return TRUE;
- }
- else
- {if(!SAM.positive())
- return smHasLessMag(SMI);
- else
- return smHasMoreMag(SMI);
- }
- }
-
- // Increment
-
- void bigIntegerG::
- smIncExtend ()
- {if(SAM.size() == MaxSize)
- smGrowMag(MaxSize + 4);
- SAM.magnitude(SAM.size()) = 1;
- SAM.incSize();
- }
-
- void bigIntegerG::
- smIncMag ()
- {unsigned long Carry = 1;
- for(unsigned int UI = 0; UI < SAM.size() && Carry; ++UI)
- Carry = !(SAM.magnitude(UI) += 1);
- if(Carry)
- smIncExtend();
- }
-
- void bigIntegerG::
- smIncMag (unsigned long UL)
- {unsigned long Carry = SAM.magnitude(0) > ~UL;
- SAM.magnitude(0) += UL;
- for(unsigned int UI = 1; Carry && UI < SAM.size(); ++UI)
- Carry = !(SAM.magnitude(UI) += 1);
- if(Carry)
- smIncExtend();
- }
-
- void bigIntegerG::
- smIncMag (const signMagnitudeP& SMI)
- {unsigned long Carry = 0;
- unsigned int Size = (SAM.size() < SMI.size()) ? SAM.size() : SMI.size();
- for(unsigned int UI = 0; UI < Size; ++UI)
- {if(Carry)
- {Carry = (SAM.magnitude(UI) >= ~SMI.magnitude(UI));
- SAM.magnitude(UI) += SMI.magnitude(UI) + 1;
- }
- else
- {Carry = (SAM.magnitude(UI) > ~SMI.magnitude(UI));
- SAM.magnitude(UI) += SMI.magnitude(UI);
- }
- }
- if(SMI.size() > Size)
- {if(SMI.size() + Carry > MaxSize)
- smGrowMag(SMI.size() + 4);
- SAM.size(SMI.size());
- for(; UI < SAM.size(); ++UI)
- {SAM.magnitude(UI) = SMI.magnitude(UI) + Carry;
- Carry = Carry && !SAM.magnitude(UI);
- }
- if(Carry)
- {SAM.magnitude(SAM.size()) = 1;
- SAM.incSize();
- }
- }
- else
- {for(; Carry && UI < SAM.size(); ++UI)
- Carry = !(SAM.magnitude(UI) += 1);
- if(Carry)
- smIncExtend();
- }
- }
-
- void bigIntegerG::
- smInc (const signMagnitudeP& SMI)
- {if(SAM.zero())
- smReset(SMI);
- else if(SAM.positive() == SMI.positive())
- {if(&SAM == &SMI) smShiftLeft(1);
- else smIncMag(SMI);
- }
- else smDecMag(SMI);
- }
-
- // Decrement
-
- void bigIntegerG::
- smDecMag ()
- {if(SAM.zero())
- {SAM.magnitude(0) = 1;
- SAM.positive(0);
- }
- else
- {unsigned long Carry = 1;
- for(unsigned int UI = 0; Carry && UI < SAM.size(); ++UI)
- {Carry = !SAM.magnitude(UI);
- SAM.magnitude(UI) -= 1;
- }
- for(UI = SAM.size()-1; !SAM.magnitude(UI) && UI > 0; --UI);
- SAM.size(UI + 1);
- }
- }
-
- void bigIntegerG::
- smDecMag (unsigned long UL)
- {if(SAM.size() > 1)
- {unsigned long Carry = (SAM.magnitude(0) < UL ? 1 : 0);
- SAM.magnitude(0) -= UL;
- if(Carry)
- {for(unsigned int UI = 1; Carry && UI < SAM.size(); ++UI)
- {Carry = !SAM.magnitude(UI);
- SAM.magnitude(UI) -= 1;
- }
- for(UI = SAM.size()-1; !SAM.magnitude(UI) && UI > 0; --UI);
- SAM.size(UI + 1);
- }
- }
- else
- {if(SAM.magnitude(0) >= UL)
- SAM.magnitude(0) -= UL;
- else
- {SAM.magnitude(0) = UL - SAM.magnitude(0);
- SAM.negate();
- }
- }
- }
-
- void bigIntegerG::
- smDecMag (const signMagnitudeP& SMI)
- {unsigned long Carry = 0;
- if(smHasLessMag(SMI))
- {SAM.negate();
- if(SMI.size() > MaxSize)
- smGrowMag(SMI.size() + 4);
- for(unsigned int UI = 0; UI < SAM.size(); ++UI)
- {if(Carry)
- {Carry = SMI.magnitude(UI) <= SAM.magnitude(UI);
- SAM.magnitude(UI) = SMI.magnitude(UI) - SAM.magnitude(UI) - 1;
- }
- else
- {Carry = SMI.magnitude(UI) < SAM.magnitude(UI);
- SAM.magnitude(UI) = SMI.magnitude(UI) - SAM.magnitude(UI);
- }
- }
- SAM.size(SMI.size());
- for(; UI < SMI.size(); ++UI)
- {if(Carry)
- {Carry = !SMI.magnitude(UI);
- SAM.magnitude(UI) = SMI.magnitude(UI) - 1;
- }
- else
- SAM.magnitude(UI) = SMI.magnitude(UI);
- }
- if(SAM.size() > 1 && !SAM.magnitude(SAM.size()-1))
- SAM.decSize();
- }
- else
- {for(unsigned int UI = 0; UI < SMI.size(); ++UI)
- {if(Carry)
- {Carry = SAM.magnitude(UI) <= SMI.magnitude(UI);
- SAM.magnitude(UI) -= SMI.magnitude(UI) + 1;
- }
- else
- {Carry = SAM.magnitude(UI) < SMI.magnitude(UI);
- SAM.magnitude(UI) -= SMI.magnitude(UI);
- }
- }
- for(; Carry; ++UI)
- {Carry = !SAM.magnitude(UI);
- SAM.magnitude(UI) -= 1;
- }
- for(UI = SAM.size()-1; !SAM.magnitude(UI) && UI > 0; --UI);
- SAM.size(UI + 1);
- }
- }
-
- void bigIntegerG::
- smDec (const signMagnitudeP& SMI)
- {if(SAM.zero())
- {smReset(SMI);
- SAM.negate();
- }
- else if(SAM.positive() != SMI.positive())
- {if(&SAM == &SMI) smShiftLeft(1);
- else smIncMag(SMI);
- }
- else smDecMag(SMI);
- }
-
- // Multiplication
-
- // This algorithm is based on hand multiplication, modified
- // to prevent the need to add carries within partial products
- // by producing twice the partial products by multiplying by
- // every other digit:
- // 5 6 7 8 5 6 7 8
- // * 1 2 3 4 * 1 2 3 4
- // ------------ ----------
- // 4*6 4*8 2 4 3 2
- // 4*5 4*7 2 0 2 8
- // 3*6 3*8 1 8 2 4
- // 3*5 3*7 1 5 2 1
- // 2*6 2*8 1 2 1 6
- // 2*5 2*7 1 0 1 4
- // 1*6 1*8 0 6 0 8
- // 1*5 1*7 0 5 0 7
- // --------------------- ------------------
- // 7 0 0 6 6 5 2 7 0 0 6 6 5 2
-
- void bigIntegerG::
- smMulMag (const signMagnitudeP& Mplier)
- {signMagnitudeP Mcand (SAM);
- signMagnitudeP Part (SAM.size(), 1, new unsigned long [SAM.size()]);
- MaxSize = 4 + Mcand.size() + Mplier.size();
- SAM.magnitude() = new unsigned long [MaxSize];
- SAM.magnitude(0) = 0;
- SAM.size(1);
- for(unsigned int UI = Mplier.size()-1; UI < Mplier.size(); --UI)
- {unsigned long R = HI(Mplier.magnitude(UI));
- for(unsigned int UJ = 0; UJ < Mcand.size(); ++UJ)
- Part.magnitude(UJ) = HI(Mcand.magnitude(UJ)) * R;
- smIncMag(Part);
- smShiftLeft(HALF);
- for(UJ = 0; UJ < Mcand.size(); ++UJ)
- Part.magnitude(UJ) = LO(Mcand.magnitude(UJ)) * R;
- smIncMag(Part);
- R = LO(Mplier.magnitude(UI));
- for(UJ = 0; UJ < Mcand.size(); ++UJ)
- Part.magnitude(UJ) = HI(Mcand.magnitude(UJ)) * R;
- smIncMag(Part);
- smShiftLeft(HALF);
- for(UJ = 0; UJ < Mcand.size(); ++UJ)
- Part.magnitude(UJ) = LO(Mcand.magnitude(UJ)) * R;
- smIncMag(Part);
- }
- delete [] Mcand.magnitude();
- delete [] Part.magnitude();
- }
-
- void bigIntegerG::
- smMul (const signMagnitudeP& SMI)
- {if(!SAM.zero())
- {if(SMI.zero())
- reset();
- else
- {if(!SMI.positive()) neg();
- smMulMag(SMI);
- }
- }
- }
-
- // Division
-
- inline unsigned long bigIntegerG::
- smDivRem10 ()
- {unsigned long M = 0;
- for(unsigned int UI = SAM.size()-1; UI < SAM.size(); --UI)
- {M <<= HALF;
- M |= HI(SAM.magnitude(UI));
- unsigned long H = M / 10;
- M %= 10;
- M <<= HALF;
- M |= LO(SAM.magnitude(UI));
- SAM.magnitude(UI) = (H << HALF) | (M / 10);
- M %= 10;
- }
- if(SAM.size() > 1 && !SAM.magnitude(SAM.size()-1))
- SAM.decSize();
- return M;
- }
-
- // This is based on Knuth, Art of Computer Programming, Vol 2
- // Algorithm D (division of nonnegative integers).
-
- void bigIntegerG::
- smRemDivMag (const signMagnitudeP& Dsor,
- signMagnitudeP& Quot, unsigned int& QuotMaxSize)
- {// Special case: quot = 0, rem = this
- if(smHasLessMag(Dsor))
- {if(!QuotMaxSize)
- {QuotMaxSize = 1;
- Quot.magnitude() = new unsigned long [1];
- }
- Quot.magnitude(0) = 0;
- Quot.size(1);
- return;
- }
-
- // Normalize (shift Dsor to have msb in bit 31 of a word)
- unsigned int Shift = FULL - log2(Dsor.magnitude(Dsor.size()-1)) - 1;
- smShiftLeft(Shift);
- // special case: quot = 1, rem = this-Dsor
- if(SAM.size() == Dsor.size())
- {smDecMag(Dsor);
- if(!QuotMaxSize)
- {QuotMaxSize = 1;
- Quot.magnitude() = new unsigned long [1];
- }
- Quot.magnitude(0) = 1;
- Quot.size(1);
- return;
- }
- signMagnitudeP NDsor (Dsor);
- NDsor.magnitude() = new unsigned long [Dsor.size()];
- NDsor.magnitude(0) = Dsor.magnitude(0) << Shift;
- unsigned long Carry = Dsor.magnitude(0) >> (FULL-Shift);
- for(unsigned int UI = 1; UI < Dsor.size(); ++UI)
- {NDsor.magnitude(UI) = (Dsor.magnitude(UI) << Shift) | Carry;
- Carry = Dsor.magnitude(UI) >> (FULL-Shift);
- }
- assumed(!Carry, "internal error in normalization for division");
- unsigned long Divisor = HI(NDsor.magnitude(NDsor.size()-1));
- unsigned long SubDivisor = LO(NDsor.magnitude(NDsor.size()-1));
-
- // Initialize Quotient
- unsigned int QuotMax = SAM.size() - NDsor.size() + 1;
- Quot.size(QuotMax);
- if(QuotMax > QuotMaxSize)
- {QuotMaxSize = QuotMax;
- delete [] Quot.magnitude();
- Quot.magnitude() = new unsigned long [QuotMax];
- }
-
- // Initialize Product
- signMagnitudeP Prod (SAM.size(), 1, new unsigned long [SAM.size()]);
- for(UI = 0; UI < QuotMax; ++UI)
- Prod.magnitude(UI) = 0;
-
- // First Iteration of Divide Loop (Quotient must be 0 or 1 due to norm.)
- for(UI = 0; UI < NDsor.size(); ++UI)
- Prod.magnitude(UI + QuotMax - 1) = NDsor.magnitude(UI);
- if(smHasLessMag(Prod))
- {Quot.magnitude(QuotMax-1) = 0;}
- else
- {smDecMag(Prod);
- Quot.magnitude(QuotMax-1) = 1;
- }
-
- // Subsequent Iterations of Divide Loop
- unsigned int Halves = (QuotMax-1) << 1;
- for(UI = Halves-1; UI < Halves; --UI)
- {unsigned int QIndex = UI >> 1;
- unsigned int QHalf = UI & 1U;
-
- // Estimate Quotient
- unsigned long Dividend;
- unsigned long SubDividend;
- if(QHalf)
- {Dividend = SAM .magnitude(QIndex + NDsor.size());
- SubDividend = HI(SAM .magnitude(QIndex + NDsor.size() - 1));
- }
- else
- {Dividend = UP(SAM.magnitude(QIndex + NDsor.size()))
- | HI(SAM.magnitude(QIndex + NDsor.size() - 1));
- SubDividend = LO(SAM .magnitude(QIndex + NDsor.size() - 1));
- }
- unsigned long Quotient = Dividend / Divisor;
- if(Quotient > LOWER)
- Quotient = LOWER;
-
- // Heuristic to make missed guesses more rare
- // Knuth's algorithm calls for this test to be repeated,
- // but that leads to wrong answers!
- if((Quotient*SubDivisor) > (UP(Dividend-Quotient*Divisor)|SubDividend))
- {--Quotient;}
-
- if(Quotient)
- {// Multiply
- Carry = 0;
- for(unsigned int UJ = 0; UJ < NDsor.size(); ++UJ)
- {unsigned long ProdLo = Quotient * LO(NDsor.magnitude(UJ))
- + Carry;
- unsigned long ProdHi = Quotient * HI(NDsor.magnitude(UJ))
- + HI(ProdLo);
- Carry = HI(ProdHi);
- if(QHalf)
- {Prod.magnitude(UJ+QIndex) |= UP(ProdLo);
- Prod.magnitude(UJ+QIndex+1) = LO(ProdHi);
- }
- else
- {Prod.magnitude(UJ+QIndex) = UP(ProdHi) | LO(ProdLo);}
- }
- if(QHalf)
- Prod.magnitude(NDsor.size() + QIndex) |= UP(Carry);
- else
- Prod.magnitude(NDsor.size() + QIndex) = LO(Carry);
- Prod.size(NDsor.size()+QIndex+1);
- for(UJ = Prod.size()-1; !Prod.magnitude(UJ) && UJ > 0; --UJ);
- Prod.size(UJ + 1);
-
- // Compare (rare: this is true 1/32676 of the time, per Knuth)
- while(smHasLessMag(Prod))
- {--Quotient;
- // reduce Prod by NDsor
- Carry = 0;
- for(UJ = 0; UJ < NDsor.size(); ++UJ)
- {if(QHalf)
- {unsigned long Temp = UP(Prod.magnitude(UJ+QIndex+1))
- | HI(Prod.magnitude(UJ+QIndex));
- if(Carry)
- {Carry = Temp <= NDsor.magnitude(UJ);
- Temp -= NDsor.magnitude(UJ) + 1;
- }
- else
- {Carry = Temp < NDsor.magnitude(UJ);
- Temp -= NDsor.magnitude(UJ);
- }
- Prod.magnitude(UJ+QIndex) &= LOWER;
- Prod.magnitude(UJ+QIndex) |= UP(Temp);
- Prod.magnitude(UJ+QIndex+1) &= ~LOWER;
- Prod.magnitude(UJ+QIndex+1) |= HI(Temp);
- }
- else
- {if(Carry)
- {Carry = Prod.magnitude(UJ + QIndex)
- <= NDsor.magnitude(UJ);
- Prod.magnitude(UJ+QIndex) -= NDsor.magnitude(UJ)+1;
- }
- else
- {Carry = Prod.magnitude(UJ+QIndex)
- < NDsor.magnitude(UJ);
- Prod.magnitude(UJ+QIndex) -= NDsor.magnitude(UJ);
- }
- }
- }
- if(Carry)
- {if(QHalf)
- Prod.magnitude(NDsor.size() + QIndex) -= UP(Carry);
- else
- Prod.magnitude(NDsor.size() + QIndex) -= LO(Carry);
- }
- for(UJ = Prod.size()-1; !Prod.magnitude(UJ) && UJ > 0; --UJ);
- Prod.size(UJ + 1);
- }
-
- // Subtract
- smDecMag(Prod);
- }
-
- // Record Quotient
- if(QHalf)
- {Quot.magnitude(QIndex) = UP(Quotient);}
- else
- {Quot.magnitude(QIndex) |= Quotient;}
- }
-
- for(UI = Quot.size()-1; !Quot.magnitude(UI) && UI > 0; --UI);
- Quot.size(UI + 1);
-
- // Unnormalize
- if(Shift)
- smShiftRight(Shift);
- delete [] Prod.magnitude();
- delete [] NDsor.magnitude();
- }
-
- void bigIntegerG::
- smDiv (const signMagnitudeP& SMI)
- {signMagnitudeP Quotient;
- unsigned int QMaxSize = 0;
- smRemDivMag(SMI, Quotient, QMaxSize);
- if(!SMI.positive()) SAM.negate();
- delete [] SAM.magnitude();
- SAM.magnitude() = Quotient.magnitude();
- SAM.size(Quotient.size());
- MaxSize = QMaxSize;
- }
-
- // Output
-
- char * bigIntegerG::
- string (char* Buffer, int N, char Sep) const
- {assumed(N > 2, "string() called with N <= 2");
- Buffer[--N] = '\0';
- if(hasZero())
- Buffer[--N] = '0';
- else
- {bigIntegerA I = (bigIntegerA&)makeCopy(FALSE);
- if(Sep)
- {int Count = 3;
- while(!I.hasZero() && N)
- {if(!Count)
- {Buffer[--N] = Sep;
- Count = 3;
- }
- Buffer[--N] = '0' + char(I.guts()->smDivRem10());
- --Count;
- }
- if(hasNegative() && N)
- Buffer[--N] = '-';
- }
- else
- {while(!I.hasZero() && N)
- Buffer[--N] = '0' + char(I.guts()->smDivRem10());
- if(hasNegative() && N)
- Buffer[--N] = '-';
- }
- }
- return &Buffer[N];
- }
-
- //***************************************************************************
-