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