1 
2 /* @(#)e_hypot.c 5.1 93/09/24 */
3 /*
4  * ====================================================
5  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
6  *
7  * Developed at SunPro, a Sun Microsystems, Inc. business.
8  * Permission to use, copy, modify, and distribute this
9  * software is freely granted, provided that this notice
10  * is preserved.
11  * ====================================================
12  */
13 
14 /*
15 FUNCTION
16         <<hypot>>, <<hypotf>>---distance from origin
17 INDEX
18         hypot
19 INDEX
20         hypotf
21 
22 ANSI_SYNOPSIS
23         #include <math.h>
24         double hypot(double <[x]>, double <[y]>);
25         float hypotf(float <[x]>, float <[y]>);
26 
27 TRAD_SYNOPSIS
28         double hypot(<[x]>, <[y]>)
29         double <[x]>, <[y]>;
30 
31         float hypotf(<[x]>, <[y]>)
32         float <[x]>, <[y]>;
33 
34 DESCRIPTION
35         <<hypot>> calculates the Euclidean distance
36         @tex
37         $\sqrt{x^2+y^2}$
38         @end tex
39         @ifnottex
40         <<sqrt(<[x]>*<[x]> + <[y]>*<[y]>)>>
41         @end ifnottex
42         between the origin (0,0) and a point represented by the
43         Cartesian coordinates (<[x]>,<[y]>).  <<hypotf>> differs only
44         in the type of its arguments and result.
45 
46 RETURNS
47         Normally, the distance value is returned.  On overflow,
48         <<hypot>> returns <<HUGE_VAL>> and sets <<errno>> to
49         <<ERANGE>>.
50 
51         You can change the error treatment with <<matherr>>.
52 
53 PORTABILITY
54         <<hypot>> and <<hypotf>> are not ANSI C.  */
55 
56 /* hypot(x,y)
57  *
58  * Method :
59  *	If (assume round-to-nearest) z=x*x+y*y
60  *	has error less than sqrt(2)/2 ulp, than
61  *	sqrt(z) has error less than 1 ulp (exercise).
62  *
63  *	So, compute sqrt(x*x+y*y) with some care as
64  *	follows to get the error below 1 ulp:
65  *
66  *	Assume x>y>0;
67  *	(if possible, set rounding to round-to-nearest)
68  *	1. if x > 2y  use
69  *		x1*x1+(y*y+(x2*(x+x1))) for x*x+y*y
70  *	where x1 = x with lower 32 bits cleared, x2 = x-x1; else
71  *	2. if x <= 2y use
72  *		t1*y1+((x-y)*(x-y)+(t1*y2+t2*y))
73  *	where t1 = 2x with lower 32 bits cleared, t2 = 2x-t1,
74  *	y1= y with lower 32 bits chopped, y2 = y-y1.
75  *
76  *	NOTE: scaling may be necessary if some argument is too
77  *	      large or too tiny
78  *
79  * Special cases:
80  *	hypot(x,y) is INF if x or y is +INF or -INF; else
81  *	hypot(x,y) is NAN if x or y is NAN.
82  *
83  * Accuracy:
84  * 	hypot(x,y) returns sqrt(x^2+y^2) with error less
85  * 	than 1 ulps (units in the last place)
86  */
87 
88 #include "fdlibm.h"
89 
90 #ifndef _DOUBLE_IS_32BITS
91 
92 #ifdef __STDC__
hypot(double x,double y)93 	double hypot(double x, double y)
94 #else
95 	double hypot(x,y)
96 	double x, y;
97 #endif
98 {
99 	double a=x,b=y,t1,t2,y1,y2,w;
100 	__int32_t j,k,ha,hb;
101 
102 	GET_HIGH_WORD(ha,x);
103 	ha &= 0x7fffffff;
104 	GET_HIGH_WORD(hb,y);
105 	hb &= 0x7fffffff;
106 	if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;}
107 	SET_HIGH_WORD(a,ha);	/* a <- |a| */
108 	SET_HIGH_WORD(b,hb);	/* b <- |b| */
109 	if((ha-hb)>0x3c00000) {return a+b;} /* x/y > 2**60 */
110 	k=0;
111 	if(ha > 0x5f300000) {	/* a>2**500 */
112 	   if(ha >= 0x7ff00000) {	/* Inf or NaN */
113 	       __uint32_t low;
114 	       w = a+b;			/* for sNaN */
115 	       GET_LOW_WORD(low,a);
116 	       if(((ha&0xfffff)|low)==0) w = a;
117 	       GET_LOW_WORD(low,b);
118 	       if(((hb^0x7ff00000)|low)==0) w = b;
119 	       return w;
120 	   }
121 	   /* scale a and b by 2**-600 */
122 	   ha -= 0x25800000; hb -= 0x25800000;	k += 600;
123 	   SET_HIGH_WORD(a,ha);
124 	   SET_HIGH_WORD(b,hb);
125 	}
126 	if(hb < 0x20b00000) {	/* b < 2**-500 */
127 	    if(hb <= 0x000fffff) {	/* subnormal b or 0 */
128 	        __uint32_t low;
129 		GET_LOW_WORD(low,b);
130 		if((hb|low)==0) return a;
131 		t1=0;
132 		SET_HIGH_WORD(t1,0x7fd00000);	/* t1=2^1022 */
133 		b *= t1;
134 		a *= t1;
135 		k -= 1022;
136 	    } else {		/* scale a and b by 2^600 */
137 	        ha += 0x25800000; 	/* a *= 2^600 */
138 		hb += 0x25800000;	/* b *= 2^600 */
139 		k -= 600;
140 		SET_HIGH_WORD(a,ha);
141 		SET_HIGH_WORD(b,hb);
142 	    }
143 	}
144     /* medium size a and b */
145 	w = a-b;
146 	if (w>b) {
147 	    t1 = 0;
148 	    SET_HIGH_WORD(t1,ha);
149 	    t2 = a-t1;
150 	    w  = sqrt(t1*t1-(b*(-b)-t2*(a+t1)));
151 	} else {
152 	    a  = a+a;
153 	    y1 = 0;
154 	    SET_HIGH_WORD(y1,hb);
155 	    y2 = b - y1;
156 	    t1 = 0;
157 	    SET_HIGH_WORD(t1,ha+0x00100000);
158 	    t2 = a - t1;
159 	    w  = sqrt(t1*y1-(w*(-w)-(t1*y2+t2*b)));
160 	}
161 	if(k!=0) {
162 	    __uint32_t high;
163 	    t1 = 1.0;
164 	    GET_HIGH_WORD(high,t1);
165 	    SET_HIGH_WORD(t1,high+(k<<20));
166 	    return t1*w;
167 	} else return w;
168 }
169 
170 #endif /* defined(_DOUBLE_IS_32BITS) */
171