1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
24  */
25 /*
26  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
27  * Use is subject to license terms.
28  */
29 
30 #include <sys/isa_defs.h>
31 #include "libm_synonyms.h"
32 #include "libm_inlines.h"
33 
34 #ifdef _LITTLE_ENDIAN
35 #define HI(x)	*(1+(int*)x)
36 #define LO(x)	*(unsigned*)x
37 #else
38 #define HI(x)	*(int*)x
39 #define LO(x)	*(1+(unsigned*)x)
40 #endif
41 
42 #ifdef __RESTRICT
43 #define restrict _Restrict
44 #else
45 #define restrict
46 #endif
47 
48 /* double hypot(double x, double y)
49  *
50  * Method :
51  *	1. Special cases:
52  *		x or y is +Inf or -Inf				=> +Inf
53  *		x or y is NaN					=> QNaN
54  *	2. Computes hypot(x,y):
55  *		hypot(x,y) = m * sqrt(xnm * xnm + ynm * ynm)
56  *	Where:
57  *		m = max(|x|,|y|)
58  *		xnm = x * (1/m)
59  *		ynm = y * (1/m)
60  *
61  *	Compute xnm * xnm + ynm * ynm by simulating
62  *	muti-precision arithmetic.
63  *
64  * Accuracy:
65  *	Maximum error observed: less than 0.872 ulp after 16.777.216.000
66  *	results.
67  */
68 
69 #define sqrt __sqrt
70 
71 extern double sqrt(double);
72 extern double fabs(double);
73 
74 static const unsigned long long LCONST[] = {
75 0x41b0000000000000ULL,	/* D2ON28 = 2 ** 28		*/
76 0x0010000000000000ULL,	/* D2ONM1022 = 2 ** -1022	*/
77 0x7fd0000000000000ULL	/* D2ONP1022 = 2 **  1022	*/
78 };
79 
80 static void
81 __vhypot_n(int n, double * restrict px, int stridex, double * restrict py,
82 	int stridey, double * restrict pz, int stridez);
83 
84 #pragma no_inline(__vhypot_n)
85 
86 #define RETURN(ret)						\
87 {								\
88 	*pz = (ret);						\
89 	py += stridey;						\
90 	pz += stridez;						\
91 	if (n_n == 0)						\
92 	{							\
93 		hx0 = HI(px);					\
94 		hy0 = HI(py);					\
95 		spx = px; spy = py; spz = pz;			\
96 		continue;					\
97 	}							\
98 	n--;							\
99 	break;							\
100 }
101 
102 void
103 __vhypot(int n, double * restrict px, int stridex, double * restrict py,
104 	int stridey, double * restrict pz, int stridez)
105 {
106 	int		hx0, hx1, hy0, j0, diff;
107 	double		x_hi, x_lo, y_hi, y_lo;
108 	double		scl = 0;
109 	double		x, y, res;
110 	double		*spx, *spy, *spz;
111 	int		n_n;
112 	double		D2ON28 = ((double*)LCONST)[0];		/* 2 ** 28	*/
113 	double		D2ONM1022 = ((double*)LCONST)[1];	/* 2 **-1022	*/
114 	double		D2ONP1022 = ((double*)LCONST)[2];	/* 2 ** 1022	*/
115 
116 	while (n > 1)
117 	{
118 		n_n = 0;
119 		spx = px;
120 		spy = py;
121 		spz = pz;
122 		hx0 = HI(px);
123 		hy0 = HI(py);
124 		for (; n > 1 ; n--)
125 		{
126 			px += stridex;
127 			hx0 &= 0x7fffffff;
128 			hy0 &= 0x7fffffff;
129 
130 			if (hx0 >= 0x7fe00000)	/* |X| >= 2**1023 or Inf or NaN */
131 			{
132 				diff = hy0 - hx0;
133 				j0 = diff >> 31;
134 				j0 = hy0 - (diff & j0);
135 				j0 &= 0x7ff00000;
136 				x = *(px - stridex);
137 				y = *py;
138 				x = fabs(x);
139 				y = fabs(y);
140 				if (j0 >= 0x7ff00000)	/* |X| or |Y| = Inf or NaN */
141 				{
142 					int lx = LO((px - stridex));
143 					int ly = LO(py);
144 					if (hx0 == 0x7ff00000 && lx == 0) res = x == y ? y : x;
145 					else if (hy0 == 0x7ff00000 && ly == 0) res = x == y ? x : y;
146 					else res = x + y;
147 					RETURN (res)
148 				}
149 				else
150 				{
151 					j0 = diff >> 31;
152 					if (((diff ^ j0) - j0) < 0x03600000)	/* max(|X|,|Y|)/min(|X|,|Y|) < 2**54 */
153 					{
154 						x *= D2ONM1022;
155 						y *= D2ONM1022;
156 
157 						x_hi = (x + D2ON28) - D2ON28;
158 						x_lo = x - x_hi;
159 						y_hi = (y + D2ON28) - D2ON28;
160 						y_lo = y - y_hi;
161 						res = (x_hi * x_hi + y_hi * y_hi);
162 						res += ((x + x_hi) * x_lo + (y + y_hi) * y_lo);
163 
164 						res = sqrt (res);
165 
166 						res = D2ONP1022 * res;
167 						RETURN (res)
168 					}
169 					else RETURN (x + y)
170 				}
171 			}
172 			if (hy0 >= 0x7fe00000)	/* |Y| >= 2**1023 or Inf or NaN */
173 			{
174 				diff = hy0 - hx0;
175 				j0 = diff >> 31;
176 				j0 = hy0 - (diff & j0);
177 				j0 &= 0x7ff00000;
178 				x = *(px - stridex);
179 				y = *py;
180 				x = fabs(x);
181 				y = fabs(y);
182 				if (j0 >= 0x7ff00000)	/* |X| or |Y| = Inf or NaN */
183 				{
184 					int lx = LO((px - stridex));
185 					int ly = LO(py);
186 					if (hx0 == 0x7ff00000 && lx == 0) res = x == y ? y : x;
187 					else if (hy0 == 0x7ff00000 && ly == 0) res = x == y ? x : y;
188 					else res = x + y;
189 					RETURN (res)
190 				}
191 				else
192 				{
193 					j0 = diff >> 31;
194 					if (((diff ^ j0) - j0) < 0x03600000)	/* max(|X|,|Y|)/min(|X|,|Y|) < 2**54 */
195 					{
196 						x *= D2ONM1022;
197 						y *= D2ONM1022;
198 
199 						x_hi = (x + D2ON28) - D2ON28;
200 						x_lo = x - x_hi;
201 						y_hi = (y + D2ON28) - D2ON28;
202 						y_lo = y - y_hi;
203 						res = (x_hi * x_hi + y_hi * y_hi);
204 						res += ((x + x_hi) * x_lo + (y + y_hi) * y_lo);
205 
206 						res = sqrt (res);
207 
208 						res = D2ONP1022 * res;
209 						RETURN (res)
210 					}
211 					else RETURN (x + y)
212 				}
213 			}
214 
215 			hx1 = HI(px);
216 
217 			if (hx0 < 0x00100000 && hy0 < 0x00100000)	/* X and Y are subnormal */
218 			{
219 				x = *(px - stridex);
220 				y = *py;
221 
222 				x *= D2ONP1022;
223 				y *= D2ONP1022;
224 
225 				x_hi = (x + D2ON28) - D2ON28;
226 				x_lo = x - x_hi;
227 				y_hi = (y + D2ON28) - D2ON28;
228 				y_lo = y - y_hi;
229 				res = (x_hi * x_hi + y_hi * y_hi);
230 				res += ((x + x_hi) * x_lo + (y + y_hi) * y_lo);
231 
232 				res = sqrt(res);
233 
234 				res = D2ONM1022 * res;
235 				RETURN (res)
236 			}
237 
238 			hx0 = hx1;
239 			py += stridey;
240 			pz += stridez;
241 			n_n++;
242 			hy0 = HI(py);
243 		}
244 		if (n_n > 0)
245 			__vhypot_n (n_n, spx, stridex, spy, stridey, spz, stridez);
246 	}
247 
248 	if (n > 0)
249 	{
250 		x = *px;
251 		y = *py;
252 		hx0 = HI(px);
253 		hy0 = HI(py);
254 
255 		hx0 &= 0x7fffffff;
256 		hy0 &= 0x7fffffff;
257 
258 		diff = hy0 - hx0;
259 		j0 = diff >> 31;
260 		j0 = hy0 - (diff & j0);
261 		j0 &= 0x7ff00000;
262 
263 		if (j0 >= 0x7fe00000)	/* max(|X|,|Y|) >= 2**1023 or X or Y = Inf or NaN */
264 		{
265 			x = fabs(x);
266 			y = fabs(y);
267 			if (j0 >= 0x7ff00000)	/* |X| or |Y| = Inf or NaN */
268 			{
269 				int lx = LO(px);
270 				int ly = LO(py);
271 				if (hx0 == 0x7ff00000 && lx == 0) res = x == y ? y : x;
272 				else if (hy0 == 0x7ff00000 && ly == 0) res = x == y ? x : y;
273 				else res = x + y;
274 				*pz = res;
275 				return;
276 			}
277 			else
278 			{
279 				j0 = diff >> 31;
280 				if (((diff ^ j0) - j0) < 0x03600000)	/* max(|X|,|Y|)/min(|X|,|Y|) < 2**54 */
281 				{
282 					x *= D2ONM1022;
283 					y *= D2ONM1022;
284 
285 					x_hi = (x + D2ON28) - D2ON28;
286 					x_lo = x - x_hi;
287 					y_hi = (y + D2ON28) - D2ON28;
288 					y_lo = y - y_hi;
289 					res = (x_hi * x_hi + y_hi * y_hi);
290 					res += ((x + x_hi) * x_lo + (y + y_hi) * y_lo);
291 
292 					res = sqrt (res);
293 
294 					res = D2ONP1022 * res;
295 					*pz = res;
296 					return;
297 				}
298 				else
299 				{
300 					*pz = x + y;
301 					return;
302 				}
303 			}
304 		}
305 
306 		if (j0 < 0x00100000)	/* X and Y are subnormal */
307 		{
308 			x *= D2ONP1022;
309 			y *= D2ONP1022;
310 
311 			x_hi = (x + D2ON28) - D2ON28;
312 			x_lo = x - x_hi;
313 			y_hi = (y + D2ON28) - D2ON28;
314 			y_lo = y - y_hi;
315 			res = (x_hi * x_hi + y_hi * y_hi);
316 			res += ((x + x_hi) * x_lo + (y + y_hi) * y_lo);
317 
318 			res = sqrt(res);
319 
320 			res = D2ONM1022 * res;
321 			*pz = res;
322 			return;
323 		}
324 
325 		HI(&scl) = (0x7fe00000 - j0);
326 
327 		x *= scl;
328 		y *= scl;
329 
330 		x_hi = (x + D2ON28) - D2ON28;
331 		y_hi = (y + D2ON28) - D2ON28;
332 		x_lo = x - x_hi;
333 		y_lo = y - y_hi;
334 
335 		res = (x_hi * x_hi + y_hi * y_hi);
336 		res += ((x + x_hi) * x_lo + (y + y_hi) * y_lo);
337 
338 		res = sqrt(res);
339 
340 		HI(&scl) = j0;
341 
342 		res = scl * res;
343 		*pz = res;
344 	}
345 }
346 
347 static void
348 __vhypot_n(int n, double * restrict px, int stridex, double * restrict py,
349 	int stridey, double * restrict pz, int stridez)
350 {
351 	int		hx0, hy0, j0, diff0;
352 	double		x_hi0, x_lo0, y_hi0, y_lo0, scl0 = 0;
353 	double		x0, y0, res0;
354 	double		D2ON28 = ((double*)LCONST)[0];		/* 2 ** 28	*/
355 
356 	for(; n > 0 ; n--)
357 	{
358 		x0 = *px;
359 		y0 = *py;
360 		hx0 = HI(px);
361 		hy0 = HI(py);
362 
363 		hx0 &= 0x7fffffff;
364 		hy0 &= 0x7fffffff;
365 
366 		diff0 = hy0 - hx0;
367 		j0 = diff0 >> 31;
368 		j0 = hy0 - (diff0 & j0);
369 		j0 &= 0x7ff00000;
370 
371 		px += stridex;
372 		py += stridey;
373 
374 		HI(&scl0) = (0x7fe00000 - j0);
375 
376 		x0 *= scl0;
377 		y0 *= scl0;
378 
379 		x_hi0 = (x0 + D2ON28) - D2ON28;
380 		y_hi0 = (y0 + D2ON28) - D2ON28;
381 		x_lo0 = x0 - x_hi0;
382 		y_lo0 = y0 - y_hi0;
383 
384 		res0 = (x_hi0 * x_hi0 + y_hi0 * y_hi0);
385 		res0 += ((x0 + x_hi0) * x_lo0 + (y0 + y_hi0) * y_lo0);
386 
387 		res0 = sqrt(res0);
388 
389 		HI(&scl0) = j0;
390 
391 		res0 = scl0 * res0;
392 		*pz = res0;
393 
394 		pz += stridez;
395 	}
396 }
397 
398