//
// LiDIA - a library for computational number theory
//   Copyright (c) 1996 by the LiDIA Group
//
// File        : udigit_def.h
// Author      : Thomas Pfahler (TPf)
//               Volker Mueller (VM)
// Last change : TPf, Apr 10 1995, initial version
//               VM , Sep  3 1996, libI version
//		 MM , Oct  7 1996, interface version
//

//
// Arithmetical operations for type udigit.
// Use of libI kernel functions.
// RV = return value.
//

#if defined(HAVE_MAC_DIRS) || defined(__MWERKS__)
#include <LiDIA:iint.h>
#include <LiDIA:idigit.h>
#else
#include <LiDIA/iint.h>
#include <LiDIA/idigit.h>
#endif

typedef unsigned long  udigit;

#define UDIGIT_NBITS  ((SIZEOF_LONG)*8)


inline
udigit max_udigit()
{
  return (udigit)~0;
}

inline
udigit max_udigit_modulus()
{
  return (udigit)~0;
}

inline
unsigned int bits_per_udigit()
{
  return (unsigned int)UDIGIT_NBITS;
}

inline
unsigned int bits_per_udigit_modulus()
{
  return (unsigned int)UDIGIT_NBITS;
}


inline
udigit udigit_add(udigit & sum,
                  udigit a, udigit b, udigit carry = 0)
        //RV * 2^base + sum = a + b + carry
{
return DigitAdd(&sum, a, b, carry); 
}

inline
udigit udigit_subtract(udigit & diff, 
                  udigit a, udigit b,
                  udigit carry = 0)
        //-RV * 2^base + diff = a - b - carry
{
 return DigitSub(&diff, a, b, carry);
}

inline
udigit udigit_multiply(udigit & prod, 
                  udigit a, udigit b)
        //RV * 2^base + prod = a * b
{
return DigitMult(& prod, a, b);
}

inline
udigit udigit_divide(udigit & quot, 
                  udigit a1, udigit a0, udigit b)
       //a1 * 2^base + a0 = quot * b + RV
       //a1 must be less than b
{
return DigitDiv(& quot, a1, a0, b);
}



//
// modular functions, we assume that input is reduced modulo modul
//

inline
udigit udigit_add_mod(udigit a, udigit b, udigit p)
		//RV = (a + b) % p
		//assumes a,b < p
{
  udigit carry, rem;
  
  carry = DigitAdd(&rem, a, b, 0);
  
  if (carry)
    rem = (max_udigit() - p) + 1 + rem;
  else
    if (rem >= p)
      rem = rem - p;
  
  return rem;
}

inline
udigit udigit_subtract_mod(udigit a, udigit b, udigit p)
		//RV = (a - b) % p
		//assumes a,b < p
{
  udigit rem;
  if (a >= b)
    rem = a - b;
  else
    rem = (p - b) + a;
  return rem;
}

inline
udigit udigit_multiply_mod(udigit a, udigit b, udigit p)
          // a,b must be less than p
{
  udigit high, low;
  high = DigitMult(&low, a, b);
  return DigitDiv(&low, high, low, p);
}









