/* Integer Version 2.0, TP, 5.10.94     ilib.c  */

#include "iint.h"

void
IasIpowD(x, a, n)
  register pInteger x;
  register const Integer *a;
  DigitType n;
{
  Integer y, h;
  DigitType m;

  if (Ieq0(a))
    Ias0(x);
  else if (Ieq1(a))
    Ias1(x);
  else
  {
    cI(&h);
    cI(&y);
    IasI(&y, a);
    Ias1(x);
    m = n;

    while (m > 0)
    {
      if (m & 1)
	ImuasI(x, &y);
      ImuasI(&y, &y);
      m >>= 1;
    }
    dI(&h);
    dI(&y);
  }
}

void
IassqrtI(y, x)
    pInteger y;
    const Integer *x;
{
    Integer xx, yy, q, r;

    if (Ilt0(x))
      Ierror("IassqrtI: negative argument");

    if (Ieq0(x))
	Ias0(y);
    else if (Ieq1(x))
	Ias1(y);
    else
    {
	cI(&q);
	cI(&r);

	cIasI(&xx, x);

	IasI(y, x);
	Isr1(y);
	cIasI(&yy, y);

	for (;;)
	{
	    uIdiv(&q, &r, &xx, &yy);
	    if (IgeI(&q, &yy))
	    {
		IasI(y, &yy);
		break;
	    }
	    else
	    {
		IplasI(&yy, &q);
		Isr1(&yy);
	    }
	}
	dI(&xx);
	dI(&yy);
	dI(&r);
	dI(&q);
    }
}

void
Iroot(y, x, n)
    register pInteger y;
    register const Integer *x;
    register DigitType n;
{
    Integer a, b;
    register DigitType nm1;

    if (Ieq0(x))
    {
      Ias0(y);
      return;
    }

    switch (n)
    {
      case 0:
	Iasint(y, 1);
	return;
      case 1:
	IasI(y, x);
      case 2:
	IassqrtI(y, x);
	return;
    }
    cI(&a);
    cI(&b);
    nm1 = n - 1;
    Iasint(y, 1);
    IslasD(y, (Ilog(x) + nm1) / n);
    do
    {
	IasIpowD(&a, y, nm1);
	Idiv(&a, &b, x, &a);
	IasImiI(&a, y, &a);
	IdiasD(&a, n);
	ImiasI(y, &a);
    } while (Igt0(&a));
    IasIpowD(&a, y, n);
    if (IgtI(&a, x))
	Idec(y);
    dI(&a);
    dI(&b);
}

