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  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
23  */
24 /*
25  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  */
28 
29 #include "libm.h"
30 #include "xpg6.h"	/* __xpg6 */
31 #include <stdio.h>
32 #include <float.h>		/* DBL_MAX, DBL_MIN */
33 #include <unistd.h>		/* write */
34 #if defined(__x86)
35 #include <ieeefp.h>
36 #undef	fp_class
37 #define	fp_class	fpclass
38 #define	fp_quiet	FP_QNAN
39 #endif
40 #include <errno.h>
41 #undef fflush
42 #include <sys/isa_defs.h>
43 
44 /* INDENT OFF */
45 /*
46  * Report libm exception error according to System V Interface Definition
47  * (SVID).
48  * Error mapping:
49  *	1 -- acos(|x|>1)
50  *	2 -- asin(|x|>1)
51  *	3 -- atan2(+-0,+-0)
52  *	4 -- hypot overflow
53  *	5 -- cosh overflow
54  *	6 -- exp overflow
55  *	7 -- exp underflow
56  *	8 -- y0(0)
57  *	9 -- y0(-ve)
58  *	10-- y1(0)
59  *	11-- y1(-ve)
60  *	12-- yn(0)
61  *	13-- yn(-ve)
62  *	14-- lgamma(finite) overflow
63  *	15-- lgamma(-integer)
64  *	16-- log(0)
65  *	17-- log(x<0)
66  *	18-- log10(0)
67  *	19-- log10(x<0)
68  *	20-- pow(0.0,0.0)
69  *	21-- pow(x,y) overflow
70  *	22-- pow(x,y) underflow
71  *	23-- pow(0,negative)
72  *	24-- pow(neg,non-integral)
73  *	25-- sinh(finite) overflow
74  *	26-- sqrt(negative)
75  *	27-- fmod(x,0)
76  *	28-- remainder(x,0)
77  *	29-- acosh(x<1)
78  *	30-- atanh(|x|>1)
79  *	31-- atanh(|x|=1)
80  *	32-- scalb overflow
81  *	33-- scalb underflow
82  *	34-- j0(|x|>X_TLOSS)
83  *	35-- y0(x>X_TLOSS)
84  *	36-- j1(|x|>X_TLOSS)
85  *	37-- y1(x>X_TLOSS)
86  *	38-- jn(|x|>X_TLOSS, n)
87  *	39-- yn(x>X_TLOSS, n)
88  *	40-- gamma(finite) overflow
89  *	41-- gamma(-integer)
90  *	42-- pow(NaN,0.0) return NaN for SVID/XOPEN
91  *	43-- log1p(-1)
92  *	44-- log1p(x<-1)
93  *	45-- logb(0)
94  *	46-- nextafter overflow
95  *	47-- scalb(x,inf)
96  */
97 /* INDENT ON */
98 
99 static double setexception(int, double);
100 
101 static const union {
102 	unsigned	x[2];
103 	double		d;
104 } C[] = {
105 #ifdef _LITTLE_ENDIAN
106 	{ 0xffffffff, 0x7fffffff },
107 	{ 0x54442d18, 0x400921fb },
108 #else
109 	{ 0x7fffffff, 0xffffffff },
110 	{ 0x400921fb, 0x54442d18 },
111 #endif
112 };
113 
114 #define	NaN	C[0].d
115 #define	PI_RZ	C[1].d
116 
117 #define	__HI(x)	((unsigned *)&x)[HIWORD]
118 #define	__LO(x)	((unsigned *)&x)[LOWORD]
119 #undef	Inf
120 #define	Inf	HUGE_VAL
121 
122 double
_SVID_libm_err(double x,double y,int type)123 _SVID_libm_err(double x, double y, int type) {
124 	struct exception	exc;
125 	double			t, w, ieee_retval = 0;
126 	enum version		lib_version = _lib_version;
127 	int			iy;
128 
129 	/* force libm_ieee behavior in SUSv3 mode */
130 	if ((__xpg6 & _C99SUSv3_math_errexcept) != 0)
131 		lib_version = libm_ieee;
132 	if (lib_version == c_issue_4) {
133 		(void) fflush(stdout);
134 	}
135 	exc.arg1 = x;
136 	exc.arg2 = y;
137 	switch (type) {
138 	case 1:
139 		/* acos(|x|>1) */
140 		exc.type = DOMAIN;
141 		exc.name = "acos";
142 		ieee_retval = setexception(3, 1.0);
143 		exc.retval = 0.0;
144 		if (lib_version == strict_ansi) {
145 			errno = EDOM;
146 		} else if (!matherr(&exc)) {
147 			if (lib_version == c_issue_4) {
148 				(void) write(2, "acos: DOMAIN error\n", 19);
149 			}
150 			errno = EDOM;
151 		}
152 		break;
153 	case 2:
154 		/* asin(|x|>1) */
155 		exc.type = DOMAIN;
156 		exc.name = "asin";
157 		exc.retval = 0.0;
158 		ieee_retval = setexception(3, 1.0);
159 		if (lib_version == strict_ansi) {
160 			errno = EDOM;
161 		} else if (!matherr(&exc)) {
162 			if (lib_version == c_issue_4) {
163 				(void) write(2, "asin: DOMAIN error\n", 19);
164 			}
165 			errno = EDOM;
166 		}
167 		break;
168 	case 3:
169 		/* atan2(+-0,+-0) */
170 		exc.arg1 = y;
171 		exc.arg2 = x;
172 		exc.type = DOMAIN;
173 		exc.name = "atan2";
174 		ieee_retval = copysign(1.0, x) == 1.0 ? y :
175 			copysign(PI_RZ + DBL_MIN, y);
176 		exc.retval = 0.0;
177 		if (lib_version == strict_ansi) {
178 			errno = EDOM;
179 		} else if (!matherr(&exc)) {
180 			if (lib_version == c_issue_4) {
181 				(void) write(2, "atan2: DOMAIN error\n", 20);
182 			}
183 			errno = EDOM;
184 		}
185 		break;
186 	case 4:
187 		/* hypot(finite,finite) overflow */
188 		exc.type = OVERFLOW;
189 		exc.name = "hypot";
190 		ieee_retval = Inf;
191 		if (lib_version == c_issue_4)
192 			exc.retval = HUGE;
193 		else
194 			exc.retval = HUGE_VAL;
195 		if (lib_version == strict_ansi)
196 			errno = ERANGE;
197 		else if (!matherr(&exc))
198 			errno = ERANGE;
199 		break;
200 	case 5:
201 		/* cosh(finite) overflow */
202 		exc.type = OVERFLOW;
203 		exc.name = "cosh";
204 		ieee_retval = setexception(2, 1.0);
205 		if (lib_version == c_issue_4)
206 			exc.retval = HUGE;
207 		else
208 			exc.retval = HUGE_VAL;
209 		if (lib_version == strict_ansi)
210 			errno = ERANGE;
211 		else if (!matherr(&exc))
212 			errno = ERANGE;
213 		break;
214 	case 6:
215 		/* exp(finite) overflow */
216 		exc.type = OVERFLOW;
217 		exc.name = "exp";
218 		ieee_retval = setexception(2, 1.0);
219 		if (lib_version == c_issue_4)
220 			exc.retval = HUGE;
221 		else
222 			exc.retval = HUGE_VAL;
223 		if (lib_version == strict_ansi)
224 			errno = ERANGE;
225 		else if (!matherr(&exc))
226 			errno = ERANGE;
227 		break;
228 	case 7:
229 		/* exp(finite) underflow */
230 		exc.type = UNDERFLOW;
231 		exc.name = "exp";
232 		ieee_retval = setexception(1, 1.0);
233 		exc.retval = 0.0;
234 		if (lib_version == strict_ansi)
235 			errno = ERANGE;
236 		else if (!matherr(&exc))
237 			errno = ERANGE;
238 		break;
239 	case 8:
240 		/* y0(0) = -inf */
241 		exc.type = DOMAIN;	/* should be SING for IEEE */
242 		exc.name = "y0";
243 		ieee_retval = setexception(0, -1.0);
244 		if (lib_version == c_issue_4)
245 			exc.retval = -HUGE;
246 		else
247 			exc.retval = -HUGE_VAL;
248 		if (lib_version == strict_ansi) {
249 			errno = EDOM;
250 		} else if (!matherr(&exc)) {
251 			if (lib_version == c_issue_4) {
252 				(void) write(2, "y0: DOMAIN error\n", 17);
253 			}
254 			errno = EDOM;
255 		}
256 		break;
257 	case 9:
258 		/* y0(x<0) = NaN */
259 		exc.type = DOMAIN;
260 		exc.name = "y0";
261 		ieee_retval = setexception(3, 1.0);
262 		if (lib_version == c_issue_4)
263 			exc.retval = -HUGE;
264 		else
265 			exc.retval = -HUGE_VAL;
266 		if (lib_version == strict_ansi) {
267 			errno = EDOM;
268 		} else if (!matherr(&exc)) {
269 			if (lib_version == c_issue_4) {
270 				(void) write(2, "y0: DOMAIN error\n", 17);
271 			}
272 			errno = EDOM;
273 		}
274 		break;
275 	case 10:
276 		/* y1(0) = -inf */
277 		exc.type = DOMAIN;	/* should be SING for IEEE */
278 		exc.name = "y1";
279 		ieee_retval = setexception(0, -1.0);
280 		if (lib_version == c_issue_4)
281 			exc.retval = -HUGE;
282 		else
283 			exc.retval = -HUGE_VAL;
284 		if (lib_version == strict_ansi) {
285 			errno = EDOM;
286 		} else if (!matherr(&exc)) {
287 			if (lib_version == c_issue_4) {
288 				(void) write(2, "y1: DOMAIN error\n", 17);
289 			}
290 			errno = EDOM;
291 		}
292 		break;
293 	case 11:
294 		/* y1(x<0) = NaN */
295 		exc.type = DOMAIN;
296 		exc.name = "y1";
297 		ieee_retval = setexception(3, 1.0);
298 		if (lib_version == c_issue_4)
299 			exc.retval = -HUGE;
300 		else
301 			exc.retval = -HUGE_VAL;
302 		if (lib_version == strict_ansi) {
303 			errno = EDOM;
304 		} else if (!matherr(&exc)) {
305 			if (lib_version == c_issue_4) {
306 				(void) write(2, "y1: DOMAIN error\n", 17);
307 			}
308 			errno = EDOM;
309 		}
310 		break;
311 	case 12:
312 		/* yn(n,0) = -inf */
313 		exc.type = DOMAIN;	/* should be SING for IEEE */
314 		exc.name = "yn";
315 		ieee_retval = setexception(0, -1.0);
316 		if (lib_version == c_issue_4)
317 			exc.retval = -HUGE;
318 		else
319 			exc.retval = -HUGE_VAL;
320 		if (lib_version == strict_ansi) {
321 			errno = EDOM;
322 		} else if (!matherr(&exc)) {
323 			if (lib_version == c_issue_4) {
324 				(void) write(2, "yn: DOMAIN error\n", 17);
325 			}
326 			errno = EDOM;
327 		}
328 		break;
329 	case 13:
330 		/* yn(x<0) = NaN */
331 		exc.type = DOMAIN;
332 		exc.name = "yn";
333 		ieee_retval = setexception(3, 1.0);
334 		if (lib_version == c_issue_4)
335 			exc.retval = -HUGE;
336 		else
337 			exc.retval = -HUGE_VAL;
338 		if (lib_version == strict_ansi) {
339 			errno = EDOM;
340 		} else if (!matherr(&exc)) {
341 			if (lib_version == c_issue_4) {
342 				(void) write(2, "yn: DOMAIN error\n", 17);
343 			}
344 			errno = EDOM;
345 		}
346 		break;
347 	case 14:
348 		/* lgamma(finite) overflow */
349 		exc.type = OVERFLOW;
350 		exc.name = "lgamma";
351 		ieee_retval = setexception(2, 1.0);
352 		if (lib_version == c_issue_4)
353 			exc.retval = HUGE;
354 		else
355 			exc.retval = HUGE_VAL;
356 		if (lib_version == strict_ansi)
357 			errno = ERANGE;
358 		else if (!matherr(&exc))
359 			errno = ERANGE;
360 		break;
361 	case 15:
362 		/* lgamma(-integer) or lgamma(0) */
363 		exc.type = SING;
364 		exc.name = "lgamma";
365 		ieee_retval = setexception(0, 1.0);
366 		if (lib_version == c_issue_4)
367 			exc.retval = HUGE;
368 		else
369 			exc.retval = HUGE_VAL;
370 		if (lib_version == strict_ansi) {
371 			errno = EDOM;
372 		} else if (!matherr(&exc)) {
373 			if (lib_version == c_issue_4) {
374 				(void) write(2, "lgamma: SING error\n", 19);
375 			}
376 			errno = EDOM;
377 		}
378 		break;
379 	case 16:
380 		/* log(0) */
381 		exc.type = SING;
382 		exc.name = "log";
383 		ieee_retval = setexception(0, -1.0);
384 		if (lib_version == c_issue_4)
385 			exc.retval = -HUGE;
386 		else
387 			exc.retval = -HUGE_VAL;
388 		if (lib_version == strict_ansi) {
389 			errno = ERANGE;
390 		} else if (!matherr(&exc)) {
391 			if (lib_version == c_issue_4) {
392 				(void) write(2, "log: SING error\n", 16);
393 				errno = EDOM;
394 			} else {
395 				errno = ERANGE;
396 			}
397 		}
398 		break;
399 	case 17:
400 		/* log(x<0) */
401 		exc.type = DOMAIN;
402 		exc.name = "log";
403 		ieee_retval = setexception(3, 1.0);
404 		if (lib_version == c_issue_4)
405 			exc.retval = -HUGE;
406 		else
407 			exc.retval = -HUGE_VAL;
408 		if (lib_version == strict_ansi) {
409 			errno = EDOM;
410 		} else if (!matherr(&exc)) {
411 			if (lib_version == c_issue_4) {
412 				(void) write(2, "log: DOMAIN error\n", 18);
413 			}
414 			errno = EDOM;
415 		}
416 		break;
417 	case 18:
418 		/* log10(0) */
419 		exc.type = SING;
420 		exc.name = "log10";
421 		ieee_retval = setexception(0, -1.0);
422 		if (lib_version == c_issue_4)
423 			exc.retval = -HUGE;
424 		else
425 			exc.retval = -HUGE_VAL;
426 		if (lib_version == strict_ansi) {
427 			errno = ERANGE;
428 		} else if (!matherr(&exc)) {
429 			if (lib_version == c_issue_4) {
430 				(void) write(2, "log10: SING error\n", 18);
431 				errno = EDOM;
432 			} else {
433 				errno = ERANGE;
434 			}
435 		}
436 		break;
437 	case 19:
438 		/* log10(x<0) */
439 		exc.type = DOMAIN;
440 		exc.name = "log10";
441 		ieee_retval = setexception(3, 1.0);
442 		if (lib_version == c_issue_4)
443 			exc.retval = -HUGE;
444 		else
445 			exc.retval = -HUGE_VAL;
446 		if (lib_version == strict_ansi) {
447 			errno = EDOM;
448 		} else if (!matherr(&exc)) {
449 			if (lib_version == c_issue_4) {
450 				(void) write(2, "log10: DOMAIN error\n", 20);
451 			}
452 			errno = EDOM;
453 		}
454 		break;
455 	case 20:
456 		/* pow(0.0,0.0) */
457 		/* error only if lib_version == c_issue_4 */
458 		exc.type = DOMAIN;
459 		exc.name = "pow";
460 		exc.retval = 0.0;
461 		ieee_retval = 1.0;
462 		if (lib_version != c_issue_4) {
463 			exc.retval = 1.0;
464 		} else if (!matherr(&exc)) {
465 			(void) write(2, "pow(0,0): DOMAIN error\n", 23);
466 			errno = EDOM;
467 		}
468 		break;
469 	case 21:
470 		/* pow(x,y) overflow */
471 		exc.type = OVERFLOW;
472 		exc.name = "pow";
473 		exc.retval = (lib_version == c_issue_4)? HUGE : HUGE_VAL;
474 		if (signbit(x)) {
475 			t = rint(y);
476 			if (t == y) {
477 				w = rint(0.5 * y);
478 				if (t != w + w)	{	/* y is odd */
479 					exc.retval = -exc.retval;
480 				}
481 			}
482 		}
483 		ieee_retval = setexception(2, exc.retval);
484 		if (lib_version == strict_ansi)
485 			errno = ERANGE;
486 		else if (!matherr(&exc))
487 			errno = ERANGE;
488 		break;
489 	case 22:
490 		/* pow(x,y) underflow */
491 		exc.type = UNDERFLOW;
492 		exc.name = "pow";
493 		exc.retval = 0.0;
494 		if (signbit(x)) {
495 			t = rint(y);
496 			if (t == y) {
497 				w = rint(0.5 * y);
498 				if (t != w + w)	/* y is odd */
499 					exc.retval = -exc.retval;
500 			}
501 		}
502 		ieee_retval = setexception(1, exc.retval);
503 		if (lib_version == strict_ansi)
504 			errno = ERANGE;
505 		else if (!matherr(&exc))
506 			errno = ERANGE;
507 		break;
508 	case 23:
509 		/* (+-0)**neg */
510 		exc.type = DOMAIN;
511 		exc.name = "pow";
512 		ieee_retval = setexception(0, 1.0);
513 		{
514 			int ahy, k, j, yisint, ly, hx;
515 			/* INDENT OFF */
516 			/*
517 			 * determine if y is an odd int when x = -0
518 			 * yisint = 0       ... y is not an integer
519 			 * yisint = 1       ... y is an odd int
520 			 * yisint = 2       ... y is an even int
521 			 */
522 			/* INDENT ON */
523 			hx  = __HI(x);
524 			ahy = __HI(y)&0x7fffffff;
525 			ly  = __LO(y);
526 
527 			yisint = 0;
528 			if (ahy >= 0x43400000) {
529 				yisint = 2;	/* even integer y */
530 			} else if (ahy >= 0x3ff00000) {
531 				k = (ahy >> 20) - 0x3ff;	/* exponent */
532 				if (k > 20) {
533 					j = ly >> (52 - k);
534 					if ((j << (52 - k)) == ly)
535 						yisint = 2 - (j & 1);
536 				} else if (ly == 0) {
537 					j = ahy >> (20 - k);
538 					if ((j << (20 - k)) == ahy)
539 						yisint = 2 - (j & 1);
540 				}
541 			}
542 			if (hx < 0 && yisint == 1)
543 				ieee_retval = -ieee_retval;
544 		}
545 		if (lib_version == c_issue_4)
546 			exc.retval = 0.0;
547 		else
548 			exc.retval = -HUGE_VAL;
549 		if (lib_version == strict_ansi) {
550 			errno = EDOM;
551 		} else if (!matherr(&exc)) {
552 			if (lib_version == c_issue_4) {
553 				(void) write(2, "pow(0,neg): DOMAIN error\n",
554 				    25);
555 			}
556 			errno = EDOM;
557 		}
558 		break;
559 	case 24:
560 		/* neg**non-integral */
561 		exc.type = DOMAIN;
562 		exc.name = "pow";
563 		ieee_retval = setexception(3, 1.0);
564 		if (lib_version == c_issue_4)
565 			exc.retval = 0.0;
566 		else
567 			exc.retval = ieee_retval;	/* X/Open allow NaN */
568 		if (lib_version == strict_ansi) {
569 			errno = EDOM;
570 		} else if (!matherr(&exc)) {
571 			if (lib_version == c_issue_4) {
572 				(void) write(2,
573 				    "neg**non-integral: DOMAIN error\n", 32);
574 			}
575 			errno = EDOM;
576 		}
577 		break;
578 	case 25:
579 		/* sinh(finite) overflow */
580 		exc.type = OVERFLOW;
581 		exc.name = "sinh";
582 		ieee_retval = copysign(Inf, x);
583 		if (lib_version == c_issue_4)
584 			exc.retval = x > 0.0 ? HUGE : -HUGE;
585 		else
586 			exc.retval = x > 0.0 ? HUGE_VAL : -HUGE_VAL;
587 		if (lib_version == strict_ansi)
588 			errno = ERANGE;
589 		else if (!matherr(&exc))
590 			errno = ERANGE;
591 		break;
592 	case 26:
593 		/* sqrt(x<0) */
594 		exc.type = DOMAIN;
595 		exc.name = "sqrt";
596 		ieee_retval = setexception(3, 1.0);
597 		if (lib_version == c_issue_4)
598 			exc.retval = 0.0;
599 		else
600 			exc.retval = ieee_retval;	/* quiet NaN */
601 		if (lib_version == strict_ansi) {
602 			errno = EDOM;
603 		} else if (!matherr(&exc)) {
604 			if (lib_version == c_issue_4) {
605 				(void) write(2, "sqrt: DOMAIN error\n", 19);
606 			}
607 			errno = EDOM;
608 		}
609 		break;
610 	case 27:
611 		/* fmod(x,0) */
612 		exc.type = DOMAIN;
613 		exc.name = "fmod";
614 		if (fp_class(x) == fp_quiet)
615 			ieee_retval = NaN;
616 		else
617 			ieee_retval = setexception(3, 1.0);
618 		if (lib_version == c_issue_4)
619 			exc.retval = x;
620 		else
621 			exc.retval = ieee_retval;
622 		if (lib_version == strict_ansi) {
623 			errno = EDOM;
624 		} else if (!matherr(&exc)) {
625 			if (lib_version == c_issue_4) {
626 				(void) write(2, "fmod:  DOMAIN error\n", 20);
627 			}
628 			errno = EDOM;
629 		}
630 		break;
631 	case 28:
632 		/* remainder(x,0) */
633 		exc.type = DOMAIN;
634 		exc.name = "remainder";
635 		if (fp_class(x) == fp_quiet)
636 			ieee_retval = NaN;
637 		else
638 			ieee_retval = setexception(3, 1.0);
639 		exc.retval = NaN;
640 		if (lib_version == strict_ansi) {
641 			errno = EDOM;
642 		} else if (!matherr(&exc)) {
643 			if (lib_version == c_issue_4) {
644 				(void) write(2, "remainder: DOMAIN error\n",
645 				    24);
646 			}
647 			errno = EDOM;
648 		}
649 		break;
650 	case 29:
651 		/* acosh(x<1) */
652 		exc.type = DOMAIN;
653 		exc.name = "acosh";
654 		ieee_retval = setexception(3, 1.0);
655 		exc.retval = NaN;
656 		if (lib_version == strict_ansi) {
657 			errno = EDOM;
658 		} else if (!matherr(&exc)) {
659 			if (lib_version == c_issue_4) {
660 				(void) write(2, "acosh: DOMAIN error\n", 20);
661 			}
662 			errno = EDOM;
663 		}
664 		break;
665 	case 30:
666 		/* atanh(|x|>1) */
667 		exc.type = DOMAIN;
668 		exc.name = "atanh";
669 		ieee_retval = setexception(3, 1.0);
670 		exc.retval = NaN;
671 		if (lib_version == strict_ansi) {
672 			errno = EDOM;
673 		} else if (!matherr(&exc)) {
674 			if (lib_version == c_issue_4) {
675 				(void) write(2, "atanh: DOMAIN error\n", 20);
676 			}
677 			errno = EDOM;
678 		}
679 		break;
680 	case 31:
681 		/* atanh(|x|=1) */
682 		exc.type = SING;
683 		exc.name = "atanh";
684 		ieee_retval = setexception(0, x);
685 		exc.retval = ieee_retval;
686 		if (lib_version == strict_ansi) {
687 			errno = ERANGE;
688 		} else if (!matherr(&exc)) {
689 			if (lib_version == c_issue_4) {
690 				(void) write(2, "atanh: SING error\n", 18);
691 				errno = EDOM;
692 			} else {
693 				errno = ERANGE;
694 			}
695 		}
696 		break;
697 	case 32:
698 		/* scalb overflow; SVID also returns +-HUGE_VAL */
699 		exc.type = OVERFLOW;
700 		exc.name = "scalb";
701 		ieee_retval = setexception(2, x);
702 		exc.retval = x > 0.0 ? HUGE_VAL : -HUGE_VAL;
703 		if (lib_version == strict_ansi)
704 			errno = ERANGE;
705 		else if (!matherr(&exc))
706 			errno = ERANGE;
707 		break;
708 	case 33:
709 		/* scalb underflow */
710 		exc.type = UNDERFLOW;
711 		exc.name = "scalb";
712 		ieee_retval = setexception(1, x);
713 		exc.retval = ieee_retval;	/* +-0.0 */
714 		if (lib_version == strict_ansi)
715 			errno = ERANGE;
716 		else if (!matherr(&exc))
717 			errno = ERANGE;
718 		break;
719 	case 34:
720 		/* j0(|x|>X_TLOSS) */
721 		exc.type = TLOSS;
722 		exc.name = "j0";
723 		exc.retval = 0.0;
724 		ieee_retval = y;
725 		if (lib_version == strict_ansi) {
726 			errno = ERANGE;
727 		} else if (!matherr(&exc)) {
728 			if (lib_version == c_issue_4) {
729 				(void) write(2, exc.name, 2);
730 				(void) write(2, ": TLOSS error\n", 14);
731 			}
732 			errno = ERANGE;
733 		}
734 		break;
735 	case 35:
736 		/* y0(x>X_TLOSS) */
737 		exc.type = TLOSS;
738 		exc.name = "y0";
739 		exc.retval = 0.0;
740 		ieee_retval = y;
741 		if (lib_version == strict_ansi) {
742 			errno = ERANGE;
743 		} else if (!matherr(&exc)) {
744 			if (lib_version == c_issue_4) {
745 				(void) write(2, exc.name, 2);
746 				(void) write(2, ": TLOSS error\n", 14);
747 			}
748 			errno = ERANGE;
749 		}
750 		break;
751 	case 36:
752 		/* j1(|x|>X_TLOSS) */
753 		exc.type = TLOSS;
754 		exc.name = "j1";
755 		exc.retval = 0.0;
756 		ieee_retval = y;
757 		if (lib_version == strict_ansi) {
758 			errno = ERANGE;
759 		} else if (!matherr(&exc)) {
760 			if (lib_version == c_issue_4) {
761 				(void) write(2, exc.name, 2);
762 				(void) write(2, ": TLOSS error\n", 14);
763 			}
764 			errno = ERANGE;
765 		}
766 		break;
767 	case 37:
768 		/* y1(x>X_TLOSS) */
769 		exc.type = TLOSS;
770 		exc.name = "y1";
771 		exc.retval = 0.0;
772 		ieee_retval = y;
773 		if (lib_version == strict_ansi) {
774 			errno = ERANGE;
775 		} else if (!matherr(&exc)) {
776 			if (lib_version == c_issue_4) {
777 				(void) write(2, exc.name, 2);
778 				(void) write(2, ": TLOSS error\n", 14);
779 			}
780 			errno = ERANGE;
781 		}
782 		break;
783 	case 38:
784 		/* jn(|x|>X_TLOSS) */
785 		/* incorrect ieee value: ieee should never be here */
786 		exc.type = TLOSS;
787 		exc.name = "jn";
788 		exc.retval = 0.0;
789 		ieee_retval = 0.0;	/* shall not be used */
790 		if (lib_version == strict_ansi) {
791 			errno = ERANGE;
792 		} else if (!matherr(&exc)) {
793 			if (lib_version == c_issue_4) {
794 				(void) write(2, exc.name, 2);
795 				(void) write(2, ": TLOSS error\n", 14);
796 			}
797 			errno = ERANGE;
798 		}
799 		break;
800 	case 39:
801 		/* yn(x>X_TLOSS) */
802 		/* incorrect ieee value: ieee should never be here */
803 		exc.type = TLOSS;
804 		exc.name = "yn";
805 		exc.retval = 0.0;
806 		ieee_retval = 0.0;	/* shall not be used */
807 		if (lib_version == strict_ansi) {
808 			errno = ERANGE;
809 		} else if (!matherr(&exc)) {
810 			if (lib_version == c_issue_4) {
811 				(void) write(2, exc.name, 2);
812 				(void) write(2, ": TLOSS error\n", 14);
813 			}
814 			errno = ERANGE;
815 		}
816 		break;
817 	case 40:
818 		/* gamma(finite) overflow */
819 		exc.type = OVERFLOW;
820 		exc.name = "gamma";
821 		ieee_retval = setexception(2, 1.0);
822 		if (lib_version == c_issue_4)
823 			exc.retval = HUGE;
824 		else
825 			exc.retval = HUGE_VAL;
826 		if (lib_version == strict_ansi)
827 			errno = ERANGE;
828 		else if (!matherr(&exc))
829 			errno = ERANGE;
830 		break;
831 	case 41:
832 		/* gamma(-integer) or gamma(0) */
833 		exc.type = SING;
834 		exc.name = "gamma";
835 		ieee_retval = setexception(0, 1.0);
836 		if (lib_version == c_issue_4)
837 			exc.retval = HUGE;
838 		else
839 			exc.retval = HUGE_VAL;
840 		if (lib_version == strict_ansi) {
841 			errno = EDOM;
842 		} else if (!matherr(&exc)) {
843 			if (lib_version == c_issue_4) {
844 				(void) write(2, "gamma: SING error\n", 18);
845 			}
846 			errno = EDOM;
847 		}
848 		break;
849 	case 42:
850 		/* pow(NaN,0.0) */
851 		/* error if lib_version == c_issue_4 or ansi_1 */
852 		exc.type = DOMAIN;
853 		exc.name = "pow";
854 		exc.retval = x;
855 		ieee_retval = 1.0;
856 		if (lib_version == strict_ansi) {
857 			exc.retval = 1.0;
858 		} else if (!matherr(&exc)) {
859 			if ((lib_version == c_issue_4) || (lib_version == ansi_1))
860 				errno = EDOM;
861 		}
862 		break;
863 	case 43:
864 		/* log1p(-1) */
865 		exc.type = SING;
866 		exc.name = "log1p";
867 		ieee_retval = setexception(0, -1.0);
868 		if (lib_version == c_issue_4)
869 			exc.retval = -HUGE;
870 		else
871 			exc.retval = -HUGE_VAL;
872 		if (lib_version == strict_ansi) {
873 			errno = ERANGE;
874 		} else if (!matherr(&exc)) {
875 			if (lib_version == c_issue_4) {
876 				(void) write(2, "log1p: SING error\n", 18);
877 				errno = EDOM;
878 			} else {
879 				errno = ERANGE;
880 			}
881 		}
882 		break;
883 	case 44:
884 		/* log1p(x<-1) */
885 		exc.type = DOMAIN;
886 		exc.name = "log1p";
887 		ieee_retval = setexception(3, 1.0);
888 		exc.retval = ieee_retval;
889 		if (lib_version == strict_ansi) {
890 			errno = EDOM;
891 		} else if (!matherr(&exc)) {
892 			if (lib_version == c_issue_4) {
893 				(void) write(2, "log1p: DOMAIN error\n", 20);
894 			}
895 			errno = EDOM;
896 		}
897 		break;
898 	case 45:
899 		/* logb(0) */
900 		exc.type = DOMAIN;
901 		exc.name = "logb";
902 		ieee_retval = setexception(0, -1.0);
903 		exc.retval = -HUGE_VAL;
904 		if (lib_version == strict_ansi)
905 			errno = EDOM;
906 		else if (!matherr(&exc))
907 			errno = EDOM;
908 		break;
909 	case 46:
910 		/* nextafter overflow */
911 		exc.type = OVERFLOW;
912 		exc.name = "nextafter";
913 		/*
914 		 * The value as returned by setexception is +/-DBL_MAX in
915 		 * round-to-{zero,-/+Inf} mode respectively, which is not
916 		 * usable.
917 		 */
918 		(void) setexception(2, x);
919 		ieee_retval = x > 0 ? Inf : -Inf;
920 		exc.retval = x > 0 ? HUGE_VAL : -HUGE_VAL;
921 		if (lib_version == strict_ansi)
922 			errno = ERANGE;
923 		else if (!matherr(&exc))
924 			errno = ERANGE;
925 		break;
926 	case 47:
927 		/* scalb(x,inf) */
928 		iy = ((int *)&y)[HIWORD];
929 		if (lib_version == c_issue_4)
930 			/* SVID3: ERANGE in all cases */
931 			errno = ERANGE;
932 		else if ((x == 0.0 && iy > 0) || (!finite(x) && iy < 0))
933 			/* EDOM for scalb(0,+inf) or scalb(inf,-inf) */
934 			errno = EDOM;
935 		exc.retval = ieee_retval = ((iy < 0)? x / -y : x * y);
936 		break;
937 	}
938 	switch (lib_version) {
939 	case c_issue_4:
940 	case ansi_1:
941 	case strict_ansi:
942 		return (exc.retval);
943 		/* NOTREACHED */
944 	default:
945 		return (ieee_retval);
946 	}
947 	/* NOTREACHED */
948 }
949 
950 static double
setexception(int n,double x)951 setexception(int n, double x) {
952 	/*
953 	 * n =
954 	 * 0	division by zero
955 	 * 1	underflow
956 	 * 2	overflow
957 	 * 3	invalid
958 	 */
959 	volatile double one = 1.0, zero = 0.0, retv;
960 
961 	switch (n) {
962 	case 0:		/* division by zero */
963 		retv = copysign(one / zero, x);
964 		break;
965 	case 1:		/* underflow */
966 		retv = DBL_MIN * copysign(DBL_MIN, x);
967 		break;
968 	case 2:		/* overflow */
969 		retv = DBL_MAX * copysign(DBL_MAX, x);
970 		break;
971 	case 3:		/* invalid */
972 		retv = zero * Inf;	/* for Cheetah */
973 		break;
974 	}
975 	return (retv);
976 }
977