//
// bmath.hxx
// 
// multiple precision integer arithmetic methods 
//
// Copyright (C) 1996-7 by Leonard Janke (janke@unixg.ubc.ca)

#ifndef _BMATH_HXX
#define _BMATH_HXX

#include <lmisc/lmisc.hxx>

class BMath
{ 
private: 
  static const int bitsPerUInt;
public:
  static const int SmallPrimesAvailable; // just the ones below 2000
  static const unsigned int SmallPrime[303];

  // Bit manipulation methods
  static inline void SetBit(const int bitNum, 
			    unsigned int* x, 
			    const int digits);
  static inline int TestBit(const int bitNum, 
			    const unsigned int* x, 
			    const int digits);

// Bit scan methods
  static inline int BSR(const unsigned int x);
  static inline int BSF(const unsigned int x);
  static int BSF(const unsigned int* x, const int digits);
  static int BSR(const unsigned int* x, const int digits);
  
  // Comparisons methods
  static inline char GreaterThanOrEqualTo(const unsigned int* x,
					  const unsigned int* y, 
					  int digits);
  static inline char GreaterThan(const unsigned int* x, 
				 const unsigned int* y, 
				 int digits);
  static inline char LessThanOrEqualTo(const unsigned int* x, 
				       const unsigned int* y, 
				       int digits);
  static inline char LessThan(const unsigned int* x, 
			      const unsigned int* y, 
			      int digits);
  static inline char EqualTo(const unsigned int* x, 
			     const unsigned int* y, 
			     int digits);
  static inline char NotEqualTo(const unsigned int* x, 
				const unsigned int* y, 
				int digits);
  
  // Addition methods
  static inline char BasicAdd(const unsigned int* x, 
			      const unsigned int* y, 
			      unsigned int* z, 
			      int digits); 
  static inline void RippleAdd(const unsigned int* x, 
			       const unsigned int* y, 
			       unsigned int* z, 
			       int digits);
  static char Add(const unsigned int* x, 
		  const int digitsX, 
		  const unsigned int* y, 
		  const int digitsY,
		  unsigned int* z);
  
  // Subtraction methods
  static inline char BasicSubtract(const unsigned int* x, 
				   const unsigned int* y, 
				   unsigned int* z, 
				   int digits);
  static inline void RippleSubtract(const unsigned int* x, 
				    const unsigned int* y, 
				    unsigned int* z, 
				    int digits);
  static void Subtract(const unsigned int* x, 
		       const int digitsX, 
		       const unsigned int* y, 
		       const int digitsY,
		       unsigned int* z);
  
  // Increment methods
  static inline void RippleIncrement(unsigned int* x, int digits);
  static inline char Increment(unsigned int* x, int digits);
  
  // Decrement method
  static inline void RippleDecrement(unsigned int* x, int digits);
  
  // Multiplication methods
  static inline void BasicMultiply(const unsigned int* x, 
				   const unsigned int y, 
				   unsigned int* z, 
				   int digitsX);
  static inline void MultDouble(const unsigned int* x, 
				const unsigned int* y,
				unsigned int* z);
  static void Multiply(const unsigned int* x, 
		       int digitsX, 
		       const unsigned int* y, 
		       int digitsY, 
		       unsigned int* z);
  
  // Squaring methods
  static inline void SquareDouble(const unsigned int* x,
				  unsigned int* y);
  static void Square(const unsigned int* x, 
		     const int digitsX, 
		     unsigned int* y);
  
  // Division methods
  static inline void BasicDivide(unsigned int dividendHigh, 
				 unsigned int dividendLow, 
				 unsigned int divisor, 
				 unsigned int& quotient, 
				 unsigned int& remainder);
  static void Divide(const unsigned int* dividend, 
		     const int dividendDigits, 
		     const unsigned int* divisor, 
		     const int divisorDigits,
		     unsigned int*& quotient, 
		     unsigned int*& remainder);
  
  // Specialized remainder method 
  // returns dividend%divisor
  static inline unsigned int ModSmall(const unsigned int* dividend, 
				      int digits, 
				      const unsigned int divisor); 
  
  // Bit shift methods
  static inline void ShortShiftRight(unsigned int* x, 
				     int digits, 
				     const char distance);
  static inline void ShortShiftLeft(unsigned int* x, 
				    int digits, 
				    const char distance);
  static void ShiftRight(unsigned int*& x, 
			 int& digits, 
			 const int distance); 
  static void ShiftLeft(unsigned int*& x, 
			int& digits, 
			const int distance); 

  static inline void Div2(unsigned int* x, int digits);
};

#include <linteger/bmath.asm>
#include <linteger/bmath.inl>

#endif
