/*						epow.c	*/
/*  power function: z = x**y */
/*  by Stephen L. Moshier. */


#include "ehead.h"
#define MAXPOS ((long) (((unsigned long) ~(0L)) >> 1))
#define MAXNEG (-MAXPOS)
/* #define MAXNEG (-MAXPOS - 1L) */

extern int rndprc;
void epowi();
static void epowr();


/* Run-time determination of largest integers */

int powinited = 0;
unsigned short maxposint[NE], maxnegint[NE];

void initpow()
{
long li;

li = MAXPOS;
ltoe( &li, maxposint );
li = MAXNEG;
ltoe( &li, maxnegint );
powinited = 1;
}




void epow( x, y, z )
unsigned short *x, *y, *z;
{
unsigned short w[NE];
int rndsav;
long li;

if( powinited == 0 )
	initpow();

/* Check for integer power. */

efloor( y, w );
if( (ecmp(y,w) == 0)
   && (ecmp(maxposint,w) >= 0)
   && (ecmp(w,maxnegint) >= 0) )
	{
	eifrac( y, &li, w );
	epowi( x, y, z );
	return;
	}
epowr( x, y, z );
}




/* y is integer valued. */

void epowi( x, y, z )
unsigned short x[], y[], z[];
{
unsigned short w[NE];
long li, lx;
unsigned long lu;
int rndsav;
unsigned short signx;
/* unsigned short signy; */

if( powinited == 0 )
	initpow();

rndsav = rndprc;

if( (ecmp(y,maxposint) > 0) || (ecmp(maxnegint,y) > 0) )
	{
	epowr( x, y, z );
	return;
	}

eifrac( y, &li, w );
if( li < 0 )
	lx = -li;
else
	lx = li;

/*
if( (x[NE-1] & (unsigned short )0x7fff) == 0 )
*/

if( ecmp( x, ezero) == 0 )
	{
	if( li == 0 )
		{
		emov( eone, z );
		return;
		}
	else if( li < 0 )
		{
		einfin( z );
		return;
		}
	else
		{
		eclear( z );
		return;
		}
	}

if( li == 0L )
	{
	emov( eone, z );
	return;
	}

emov( x, w );
signx = w[NE-1] & (unsigned short )0x8000;
w[NE-1] &= (unsigned short )0x7fff;

/* Overflow detection */
/*
lx = li * (w[NE-1] - 0x3fff);
if( lx > 16385L )
	{
	einfin( z );
	mtherr( "epowi", OVERFLOW );
	goto done;
	}
if( lx < -16450L )
	{
	eclear( z );
	return;
	}
*/
rndprc = NBITS;

if( li < 0 )
	{
	lu = (unsigned int )( -li );
/*	signy = 0xffff;*/
	ediv( w, eone, w );
	}
else
	{
	lu = (unsigned int )li;
/*	signy = 0;*/
	}

/* First bit of the power */
if( lu & 1 )
	{
	emov( w, z );
	}	
else
	{
	emov( eone, z );
	signx = 0;
	}


lu >>= 1;
while( lu != 0L )
	{
	emul( w, w, w );	/* arg to the 2-to-the-kth power */
	if( lu & 1L )	/* if that bit is set, then include in product */
		emul( w, z, z );
	lu >>= 1;
	}


done:

if( signx )
	eneg( z ); /* odd power of negative number */

/*
if( signy )
  	{
  	if( ecmp( z, ezero ) != 0 )
 		{
		ediv( z, eone, z );
		}
	else
		{
		einfin( z );
		printf( "epowi OVERFLOW\n" );
		}
	}
*/
rndprc = rndsav;
emul( eone, z, z );
}



/* z = exp( y * log(x) ) */

static void epowr( x, y, z )
unsigned short *x, *y, *z;
{
unsigned short w[NE];
int rndsav;

rndsav = rndprc;
rndprc = NBITS;
elog( x, w );
emul( y, w, w );
eexp( w, z );
rndprc = rndsav;
emul( eone, z, z );
}