123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- /* 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 );
- }
|