xref: /plan9-contrib/sys/src/ape/lib/ap/math/pow.c (revision 678a9e3dc62d8a797127a5e912b2bbf77c111300)
13e12c5d1SDavid du Colombier #include <math.h>
23e12c5d1SDavid du Colombier #include <errno.h>
33e12c5d1SDavid du Colombier #include <limits.h>
43e12c5d1SDavid du Colombier 
53e12c5d1SDavid du Colombier double
pow(double x,double y)63e12c5d1SDavid du Colombier pow(double x, double y) /* return x ^ y (exponentiation) */
73e12c5d1SDavid du Colombier {
83e12c5d1SDavid du Colombier 	double xy, y1, ye;
93e12c5d1SDavid du Colombier 	long i;
103e12c5d1SDavid du Colombier 	int ex, ey, flip;
113e12c5d1SDavid du Colombier 
123e12c5d1SDavid du Colombier 	if(y == 0.0)
133e12c5d1SDavid du Colombier 		return 1.0;
143e12c5d1SDavid du Colombier 
15*678a9e3dSDavid du Colombier 	/* prevent infinite loop */
16*678a9e3dSDavid du Colombier 	if(isNaN(x) || isNaN(y))
17*678a9e3dSDavid du Colombier 		return NaN();
18*678a9e3dSDavid du Colombier 	if(isInf(x, 0))
19*678a9e3dSDavid du Colombier 		return x;
20*678a9e3dSDavid du Colombier 	if(isInf(y, 0))
21*678a9e3dSDavid du Colombier 		return x == 0 || x == 1? x: y;
22*678a9e3dSDavid du Colombier 
233e12c5d1SDavid du Colombier 	flip = 0;
243e12c5d1SDavid du Colombier 	if(y < 0.){
253e12c5d1SDavid du Colombier 		y = -y;
263e12c5d1SDavid du Colombier 		flip = 1;
273e12c5d1SDavid du Colombier 	}
283e12c5d1SDavid du Colombier 	y1 = modf(y, &ye);
293e12c5d1SDavid du Colombier 	if(y1 != 0.0){
303e12c5d1SDavid du Colombier 		if(x <= 0.)
313e12c5d1SDavid du Colombier 			goto zreturn;
323e12c5d1SDavid du Colombier 		if(y1 > 0.5) {
333e12c5d1SDavid du Colombier 			y1 -= 1.;
343e12c5d1SDavid du Colombier 			ye += 1.;
353e12c5d1SDavid du Colombier 		}
363e12c5d1SDavid du Colombier 		xy = exp(y1 * log(x));
373e12c5d1SDavid du Colombier 	}else
383e12c5d1SDavid du Colombier 		xy = 1.0;
393e12c5d1SDavid du Colombier 	if(ye > LONG_MAX){
403e12c5d1SDavid du Colombier 		if(x <= 0.){
413e12c5d1SDavid du Colombier  zreturn:
423e12c5d1SDavid du Colombier 			if(x || flip)
433e12c5d1SDavid du Colombier 				errno = EDOM;
443e12c5d1SDavid du Colombier 			return 0.;
453e12c5d1SDavid du Colombier 		}
463e12c5d1SDavid du Colombier 		if(flip){
473e12c5d1SDavid du Colombier 			if(y == .5)
483e12c5d1SDavid du Colombier 				return 1./sqrt(x);
493e12c5d1SDavid du Colombier 			y = -y;
503e12c5d1SDavid du Colombier 		}else if(y == .5)
513e12c5d1SDavid du Colombier 			return sqrt(x);
523e12c5d1SDavid du Colombier 		return exp(y * log(x));
533e12c5d1SDavid du Colombier 	}
543e12c5d1SDavid du Colombier 	x = frexp(x, &ex);
553e12c5d1SDavid du Colombier 	ey = 0;
563e12c5d1SDavid du Colombier 	i = ye;
573e12c5d1SDavid du Colombier 	if(i)
583e12c5d1SDavid du Colombier 		for(;;){
593e12c5d1SDavid du Colombier 			if(i & 1){
603e12c5d1SDavid du Colombier 				xy *= x;
613e12c5d1SDavid du Colombier 				ey += ex;
623e12c5d1SDavid du Colombier 			}
633e12c5d1SDavid du Colombier 			i >>= 1;
643e12c5d1SDavid du Colombier 			if(i == 0)
653e12c5d1SDavid du Colombier 				break;
663e12c5d1SDavid du Colombier 			x *= x;
673e12c5d1SDavid du Colombier 			ex <<= 1;
683e12c5d1SDavid du Colombier 			if(x < .5){
693e12c5d1SDavid du Colombier 				x += x;
703e12c5d1SDavid du Colombier 				ex -= 1;
713e12c5d1SDavid du Colombier 			}
723e12c5d1SDavid du Colombier 		}
733e12c5d1SDavid du Colombier 	if(flip){
743e12c5d1SDavid du Colombier 		xy = 1. / xy;
753e12c5d1SDavid du Colombier 		ey = -ey;
763e12c5d1SDavid du Colombier 	}
773e12c5d1SDavid du Colombier 	errno = 0;
783e12c5d1SDavid du Colombier 	x = ldexp(xy, ey);
793e12c5d1SDavid du Colombier 	if(errno && ey < 0) {
803e12c5d1SDavid du Colombier 		errno = 0;
813e12c5d1SDavid du Colombier 		x = 0.;
823e12c5d1SDavid du Colombier 	}
833e12c5d1SDavid du Colombier 	return x;
843e12c5d1SDavid du Colombier }
85