xref: /inferno-os/libkern/pow.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsyth #include <lib9.h>
2*37da2899SCharles.Forsyth 
3*37da2899SCharles.Forsyth double
pow(double x,double y)4*37da2899SCharles.Forsyth pow(double x, double y) /* return x ^ y (exponentiation) */
5*37da2899SCharles.Forsyth {
6*37da2899SCharles.Forsyth 	double xy, y1, ye;
7*37da2899SCharles.Forsyth 	long i;
8*37da2899SCharles.Forsyth 	int ex, ey, flip;
9*37da2899SCharles.Forsyth 
10*37da2899SCharles.Forsyth 	if(y == 0.0)
11*37da2899SCharles.Forsyth 		return 1.0;
12*37da2899SCharles.Forsyth 
13*37da2899SCharles.Forsyth 	flip = 0;
14*37da2899SCharles.Forsyth 	if(y < 0.){
15*37da2899SCharles.Forsyth 		y = -y;
16*37da2899SCharles.Forsyth 		flip = 1;
17*37da2899SCharles.Forsyth 	}
18*37da2899SCharles.Forsyth 	y1 = modf(y, &ye);
19*37da2899SCharles.Forsyth 	if(y1 != 0.0){
20*37da2899SCharles.Forsyth 		if(x <= 0.)
21*37da2899SCharles.Forsyth 			goto zreturn;
22*37da2899SCharles.Forsyth 		if(y1 > 0.5) {
23*37da2899SCharles.Forsyth 			y1 -= 1.;
24*37da2899SCharles.Forsyth 			ye += 1.;
25*37da2899SCharles.Forsyth 		}
26*37da2899SCharles.Forsyth 		xy = exp(y1 * log(x));
27*37da2899SCharles.Forsyth 	}else
28*37da2899SCharles.Forsyth 		xy = 1.0;
29*37da2899SCharles.Forsyth 	if(ye > 0x7FFFFFFF){	/* should be ~0UL but compiler can't convert double to ulong */
30*37da2899SCharles.Forsyth 		if(x <= 0.){
31*37da2899SCharles.Forsyth  zreturn:
32*37da2899SCharles.Forsyth 			if(x==0. && !flip)
33*37da2899SCharles.Forsyth 				return 0.;
34*37da2899SCharles.Forsyth 			return NaN();
35*37da2899SCharles.Forsyth 		}
36*37da2899SCharles.Forsyth 		if(flip){
37*37da2899SCharles.Forsyth 			if(y == .5)
38*37da2899SCharles.Forsyth 				return 1./sqrt(x);
39*37da2899SCharles.Forsyth 			y = -y;
40*37da2899SCharles.Forsyth 		}else if(y == .5)
41*37da2899SCharles.Forsyth 			return sqrt(x);
42*37da2899SCharles.Forsyth 		return exp(y * log(x));
43*37da2899SCharles.Forsyth 	}
44*37da2899SCharles.Forsyth 	x = frexp(x, &ex);
45*37da2899SCharles.Forsyth 	ey = 0;
46*37da2899SCharles.Forsyth 	i = ye;
47*37da2899SCharles.Forsyth 	if(i)
48*37da2899SCharles.Forsyth 		for(;;){
49*37da2899SCharles.Forsyth 			if(i & 1){
50*37da2899SCharles.Forsyth 				xy *= x;
51*37da2899SCharles.Forsyth 				ey += ex;
52*37da2899SCharles.Forsyth 			}
53*37da2899SCharles.Forsyth 			i >>= 1;
54*37da2899SCharles.Forsyth 			if(i == 0)
55*37da2899SCharles.Forsyth 				break;
56*37da2899SCharles.Forsyth 			x *= x;
57*37da2899SCharles.Forsyth 			ex <<= 1;
58*37da2899SCharles.Forsyth 			if(x < .5){
59*37da2899SCharles.Forsyth 				x += x;
60*37da2899SCharles.Forsyth 				ex -= 1;
61*37da2899SCharles.Forsyth 			}
62*37da2899SCharles.Forsyth 		}
63*37da2899SCharles.Forsyth 	if(flip){
64*37da2899SCharles.Forsyth 		xy = 1. / xy;
65*37da2899SCharles.Forsyth 		ey = -ey;
66*37da2899SCharles.Forsyth 	}
67*37da2899SCharles.Forsyth 	return ldexp(xy, ey);
68*37da2899SCharles.Forsyth }
69