xref: /inferno-os/libkern/sqrt.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsyth /*
2*37da2899SCharles.Forsyth 	sqrt returns the square root of its floating
3*37da2899SCharles.Forsyth 	point argument. Newton's method.
4*37da2899SCharles.Forsyth 
5*37da2899SCharles.Forsyth 	calls frexp
6*37da2899SCharles.Forsyth */
7*37da2899SCharles.Forsyth 
8*37da2899SCharles.Forsyth #include <lib9.h>
9*37da2899SCharles.Forsyth 
10*37da2899SCharles.Forsyth double
sqrt(double arg)11*37da2899SCharles.Forsyth sqrt(double arg)
12*37da2899SCharles.Forsyth {
13*37da2899SCharles.Forsyth 	double x, temp;
14*37da2899SCharles.Forsyth 	int exp, i;
15*37da2899SCharles.Forsyth 
16*37da2899SCharles.Forsyth 	if(arg <= 0) {
17*37da2899SCharles.Forsyth 		if(arg < 0)
18*37da2899SCharles.Forsyth 			return NaN();
19*37da2899SCharles.Forsyth 		return 0;
20*37da2899SCharles.Forsyth 	}
21*37da2899SCharles.Forsyth 	if(isInf(arg, 1))
22*37da2899SCharles.Forsyth 		return arg;
23*37da2899SCharles.Forsyth 	x = frexp(arg, &exp);
24*37da2899SCharles.Forsyth 	while(x < 0.5) {
25*37da2899SCharles.Forsyth 		x *= 2;
26*37da2899SCharles.Forsyth 		exp--;
27*37da2899SCharles.Forsyth 	}
28*37da2899SCharles.Forsyth 	/*
29*37da2899SCharles.Forsyth 	 * NOTE
30*37da2899SCharles.Forsyth 	 * this wont work on 1's comp
31*37da2899SCharles.Forsyth 	 */
32*37da2899SCharles.Forsyth 	if(exp & 1) {
33*37da2899SCharles.Forsyth 		x *= 2;
34*37da2899SCharles.Forsyth 		exp--;
35*37da2899SCharles.Forsyth 	}
36*37da2899SCharles.Forsyth 	temp = 0.5 * (1.0+x);
37*37da2899SCharles.Forsyth 
38*37da2899SCharles.Forsyth 	while(exp > 60) {
39*37da2899SCharles.Forsyth 		temp *= (1L<<30);
40*37da2899SCharles.Forsyth 		exp -= 60;
41*37da2899SCharles.Forsyth 	}
42*37da2899SCharles.Forsyth 	while(exp < -60) {
43*37da2899SCharles.Forsyth 		temp /= (1L<<30);
44*37da2899SCharles.Forsyth 		exp += 60;
45*37da2899SCharles.Forsyth 	}
46*37da2899SCharles.Forsyth 	if(exp >= 0)
47*37da2899SCharles.Forsyth 		temp *= 1L << (exp/2);
48*37da2899SCharles.Forsyth 	else
49*37da2899SCharles.Forsyth 		temp /= 1L << (-exp/2);
50*37da2899SCharles.Forsyth 	for(i=0; i<=4; i++)
51*37da2899SCharles.Forsyth 		temp = 0.5*(temp + arg/temp);
52*37da2899SCharles.Forsyth 	return temp;
53*37da2899SCharles.Forsyth }
54