/*
   This file is part of Numerix.  Numerix is free software; you can
   redistribute it and/or modify it under the terms of the GNU General
   Public License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
   USA 
*/

/* +------------------------------------------------------------------------+
   |                                                                        |
   |                      Entiers de longueur arbitraire                    |
   |                                                                        |
   |                    Découpage selon une puissance de 2                  |
   |                                                                        |
   +------------------------------------------------------------------------+ */

/* M. Quercia, 31/01/2001 */

#include "long_int.h"
#include "long_int-s.h"


/* +----------------------------------------------------------------+
   |  c <- a div 2^b, d <- a mod 2^b, en conservant le signe de a   |
   |  b >= 0, capacité(c) >= la - b/HW + 1, capacité(d) >= b/HW + 1 |
   +----------------------------------------------------------------+ */

#ifndef have_sz_split
void xz(split)(entier *a, longueur b, entier *c, entier *d) {
  longueur la = Lg(a), sa = Signe(a);
  longueur lc = max(la-b/HW,0);
  longueur ld = min(la,(b+HW-1)/HW);
  longueur l;

  /* copie a dans d d'abord pour le cas où a et c seraient confondus */
  xn(move)(d->val,a->val,ld);
  if (lc > 0) xn(shr)(a->val,la,b,c->val);

  /* efface les bits en trop dans d */
  l = ld*HW - b;
  if (l > 0) d->val[ld-1] &= (1 << (HW-l)) - 1;

  /* fixe les en-têtes */
  make_head(c,lc,sa);
  make_head(d,ld,sa);
} 
#endif

   /* +---------------------------------------------------------+
      |  d <- a + b*2^c, c >= 0, capacité(d) >= max(la,lb+c)+1  |
      +---------------------------------------------------------+ */

#ifndef have_sz_join
void xz(join)(entier *a, entier *b, longueur c, entier *d) {
  longueur la = Lg(a), sa = Signe(a);
  longueur lb = Lg(b), sb = Signe(b);
  longueur q  = c/HW,  r  = c%HW;
  longueur ld; 
  ndouble ret;

  /* élimine les cas particuliers */
  if (lb == 0) {xz(move)(d,a,la); return;}
  if (la == 0) {xz(shift)(b,c,d); return;}

  /* sa <> sb ou recouvrement => ne pas ruser */
  if ((sa != sb) || (la > q+1)) {
    /* copie a s'il va être écrasé */
    if (a == d) {
      entier *aa = xz(alloc_tmp)(la);
      xz(cpy)(aa,a,la);
      xz(shift)(b,c,d);
      xz(add)(aa,d,d);
      xz(free)(aa);
    }
    else {
      xz(shift)(b,c,d);
      xz(add)(a,d,d);
    }
    return;
  }

  /* pas de recouvrement => décale et supperpose */
  if (la <= q) {
    xn(shl)(b->val,lb,r+(q-la)*HW,d->val+la);
    xn(move)(d->val, a->val,la);
    make_head(d,lb+(c+HW-1)/HW,sa);
    return;
  }

  /* recouvrement sur un mot => supperpose et additionne */
  ret = a->val[la-1];
  xn(shl)(b->val,lb,r,d->val+q);
  xn(move)(d->val, a->val,la-1);
  ld = lb + (c+HW-1)/HW;
  d->val[ld] = xn(inc_1)(d->val+q,ld-q,ret);
  make_head(d,ld+1,sa);
}
#endif
