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