#line 1 "int2adic.d"
/* Operationen mit 2-adischen Integers */

/* Multipliziert zwei Zahlen mod 2^intDsize. */
/* D_D_mult2adic_D(a,b) */
/* > uintD a,b: Zahlen mod 2^intDsize */
/* < result: Zahl c mod 2^intDsize mit c == a*b mod 2^intDsize */
  local uintD D_D_mult2adic_D (uintD a, uintD b);
#if HAVE_DD
  #define D_D_mult2adic_D(a,b)  lowD(muluD((uintD)(a),(uintD)(b)))
#else
  #if defined(GNU) || defined(INTEL)
    #define D_D_mult2adic_D(a,b)  \
      ({ var uintD __erg;              \
         muluD((a),(b), (void),__erg=);   \
         __erg;                        \
       })
  #else
    #if (intDsize==32)
      #define D_D_mult2adic_D(a,b)  mulu32_(a,b) /* lo-Teil von mulu32(a,b) */
    #else
      local uintD D_D_mult2adic_D (uintD a, uintD b)
      {
        muluD(a,b, (void),return);
      }
    #endif
  #endif
#endif

/* Potenziert eine Zahl mod 2^intDsize. */
/* D_UL_expt_D(x,y) */
/* > uintD x: Zahl mod 2^intDsize */
/* > uintL y: Exponent >0 */
/* < uintD result: x^y mod 2^intDsize */
  local uintD D_UL_expt_D (uintD x, uintL y);
/* Methode: */
/*   a:=x, b:=y, c:=1. [a^b*c bleibt invariant, = x^y.] */
/*   Solange b>1, */
/*     falls b ungerade, setze c:=a*c, */
/*     setze b:=floor(b/2), */
/*     setze a:=a*a. */
/*   Wenn b=1, setze c:=a*c. */
/*   Liefere c. */
/* Oder optimiert: */
/*   a:=x, b:=y. */
/*   Solange b gerade, setze a:=a*a, b:=b/2. [a^b bleibt invariant, = x^y.] */
/*   c:=a. */
/*   Solange b:=floor(b/2) >0 ist, */
/*     setze a:=a*a, und falls b ungerade, setze c:=a*c. */
/*   Liefere c. */
  local uintD D_UL_expt_D (uintD a, uintL b)
  {
    while ((b & bit(0)) == 0) {
      a = D_D_mult2adic_D(a,a); b = b>>1;
    }
    {var uintD c = a;
    while ((b = b>>1) != 0) {
      a = D_D_mult2adic_D(a,a);
      if (b & bit(0))
        c = D_D_mult2adic_D(a,c);
    }
    return c;
  }}

/* Dividiert zwei Zahlen mod 2^intDsize. */
/* D_D_div2adic_D(a,b) */
/* > uintD a: Zahl mod 2^intDsize */
/* > uintD b: ungerade Zahl mod 2^intDsize */
/* < result: Zahl c mod 2^intDsize mit b*c == a mod 2^intDsize */
  local uintD D_D_div2adic_D (uintD a, uintD b);
/* Methode: */
/* Konstruiere c Bit für Bit. */
/* c := 0, d := a. */
/* Für j=0,...,intDsize: */
/*   [Hier b*c == a mod 2^j und d = (a-b*c)/2^j.] j=intDsize -> fertig. */
/*   Falls d ungerade, setze c:=c+2^j und d:=(d-b)/2, sonst d:=d/2. */
/* Ergebnis c. */
#if 1
  local uintD D_D_div2adic_D (uintD a, uintD b)
  {
    ASSERT(!((b % 2) ==0));
    {var uintD c = 0;
    {var uintD bit_j = 1; /* 2^j */
    while (1) { /* Verwende a als Variable d */
      if (a & bit(0)) {
        c = c+bit_j; a = a-b;
      }
      a = a>>1;
      bit_j = bit_j << 1;
      if (bit_j == 0) /* j=intDsize -> fertig */
        break;
    }
    return c;
  }}}
#else
  local uintD D_D_div2adic_D (uintD a, uintD b)
  {
    ASSERT(!((b % 2) ==0));
    {var uintD bit_j = 1; /* 2^j */
    {var uintD b_j = b-1; /* (b-1)*2^j */
    while (1) { /* Verwende a als Variable d*2^j+c */
      if (a & bit_j)
        a = a - b_j;
      b_j = b_j << 1; bit_j = bit_j << 1;
      if (bit_j == 0) /* j=intDsize -> fertig */
        break;
    }
    return a;
  }}}
#endif

/* UDS_UDS_div2adic_UDS(len,a_LSDptr,b_LSDptr,dest_LSDptr); */
/* dividiert die UDS a_LSDptr[-len..-1] mod 2^(intDsize*len) */
/* durch die ungerade UDS b_LSDptr[-len..-1] mod 2^(intDsize*len) (len>0) */
/* und liefert den Quotienten als UDS dest_LSDptr[-len..-1] mod 2^(intDsize*len). */
  local void UDS_UDS_div2adic_UDS (uintC len, const uintD* a_LSDptr, uintD* b_LSDptr, uintD* dest_LSDptr);
/* Methode: beta=2^intDsize. Schreibe jeweils x = x[0]*beta^0 + x[1]*beta^1 + ... . */
/* Um b*c == a mod beta^m zu bestimmen: */
/* Sei b' := (b mod beta)^(-1) = b[0]^(-1), d := a. */
/* Für j=0,...,m: */
/*   [Hier ist d = a - b*c == 0 mod beta^j, und c mod beta^j bekannt.] */
/*   j=m -> fertig. */
/*   Setze c[j] := b'*d[j] mod beta, also c := c + (b'*d[j] mod beta)*beta^j. */
/*   Setze d := d - b * c[j] * beta^j. */
/* Schließlich dest := c. */
  local void UDS_UDS_div2adic_UDS (uintC len, const uintD* a_LSDptr, uintD* b_LSDptr, uintD* dest_LSDptr)
  {
    {var uintD b0inv = D_D_div2adic_D(1,b_LSDptr[-1]); /* b' */
    copy_loop_down(a_LSDptr,dest_LSDptr,len); /* d := a */
    do {
      {var uintD digit = dest_LSDptr[-1]; /* nächstes d[j] */
      #if HAVE_DD
        digit = lowD(muluD(b0inv,digit));
      #else
        muluD(b0inv,digit, (void),digit=);
      #endif
      /* digit = nächstes c[j] */
      mulusub_loop_down(digit,b_LSDptr,dest_LSDptr,len); /* d := d - b * c[j] * beta^j */
      /* Nun ist dest_LSDptr[-1] = 0. */
      *--dest_LSDptr = digit; len--; /* c[j] ablegen, nächstes j */
    }} while (len != 0);
  }}

