(root)/
glibc-2.38/
sysdeps/
powerpc/
test-arith.c
       1  /* Test floating-point arithmetic operations.
       2     Copyright (C) 1997-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  #ifndef _GNU_SOURCE
      19  #define _GNU_SOURCE
      20  #endif
      21  #include <math.h>
      22  #include <stdio.h>
      23  #include <stdlib.h>
      24  #include <string.h>
      25  #include <fenv.h>
      26  #include <assert.h>
      27  
      28  #ifndef ESIZE
      29  typedef double tocheck_t;
      30  #define ESIZE 11
      31  #define MSIZE 52
      32  #define FUNC(x) x
      33  #endif
      34  
      35  #define R_NEAREST 1
      36  #define R_ZERO 2
      37  #define R_UP 4
      38  #define R_DOWN 8
      39  #define R_ALL (R_NEAREST|R_ZERO|R_UP|R_DOWN)
      40  static fenv_t rmodes[4];
      41  static const char * const rmnames[4] =
      42  { "nearest","zero","+Inf","-Inf" };
      43  
      44  typedef union {
      45    tocheck_t tc;
      46    unsigned char c[sizeof (tocheck_t)];
      47  } union_t;
      48  
      49  /* Don't try reading these in a font that doesn't distinguish
      50     O and zero.  */
      51  typedef enum {
      52    P_Z    = 0x0,  /* 00000...0 */
      53    P_000O = 0x1,  /* 00011...1 */
      54    P_001Z = 0x2,  /* 00100...0 */
      55    P_00O  = 0x3,  /* 00111...1 */
      56    P_01Z  = 0x4,  /* 01000...0 */
      57    P_010O = 0x5,  /* 01011...1 */
      58    P_011Z = 0x6,  /* 01100...0 */
      59    P_0O   = 0x7,  /* 01111...1 */
      60    P_1Z   = 0x8,  /* 10000...0 */
      61    P_100O = 0x9,  /* 10011...1 */
      62    P_101Z = 0xa,  /* 10100...0 */
      63    P_10O  = 0xb,  /* 10111...1 */
      64    P_11Z  = 0xc,  /* 11000...0 */
      65    P_110O = 0xd,  /* 11011...1 */
      66    P_111Z = 0xe,  /* 11100...0 */
      67    P_O    = 0xf,  /* 11111...1 */
      68    P_Z1   = 0x11, /* 000...001 */
      69    P_Z10  = 0x12, /* 000...010 */
      70    P_Z11  = 0x13, /* 000...011 */
      71    P_0O00 = 0x14, /* 011...100 */
      72    P_0O01 = 0x15, /* 011...101 */
      73    P_0O0  = 0x16, /* 011...110 */
      74    P_1Z1  = 0x19, /* 100...001 */
      75    P_1Z10 = 0x1a, /* 100...010 */
      76    P_1Z11 = 0x1b, /* 100...011 */
      77    P_O00  = 0x1c, /* 111...100 */
      78    P_O01  = 0x1d, /* 111...101 */
      79    P_O0   = 0x1e, /* 111...110 */
      80    P_R    = 0x20, /* rrr...rrr */ /* ('r' means random. ) */
      81    P_Ro   = 0x21, /* rrr...rrr, with odd parity.  */
      82    P_0R   = 0x22, /* 0rr...rrr */
      83    P_1R   = 0x23, /* 1rr...rrr */
      84    P_Rno  = 0x24, /* rrr...rrr, but not all ones.  */
      85  } pattern_t;
      86  
      87  static void
      88  pattern_fill(pattern_t ptn, unsigned char *start, int bitoffset, int count)
      89  {
      90  #define bitset(count, value) \
      91        start[(count)/8] = (start[(count)/8] & ~(1 << 7-(count)%8)  \
      92                            |  (value) << 7-(count)%8)
      93    int i;
      94  
      95    if (ptn >= 0 && ptn <= 0xf)
      96      {
      97        /* Patterns between 0 and 0xF have the following format:
      98  	 The LSBit is used to fill the last n-3 bits of the pattern;
      99  	 The next 3 bits are the first 3 bits of the pattern. */
     100        for (i = 0; i < count; i++)
     101  	if (i < 3)
     102  	  bitset((bitoffset+i), ptn >> (3-i) & 1);
     103  	else
     104  	  bitset((bitoffset+i), ptn >> 0 & 1);
     105      }
     106    else if (ptn <= 0x1f)
     107      {
     108        /* Patterns between 0x10 and 0x1F have the following format:
     109  	 The two LSBits are the last two bits of the pattern;
     110  	 The 0x8 bit is the first bit of the pattern;
     111  	 The 0x4 bit is used to fill the remainder. */
     112        for (i = 0; i < count; i++)
     113  	if (i == 0)
     114  	  bitset((bitoffset+i), ptn >> 3 & 1);
     115  	else if (i >= count-2)
     116  	  bitset((bitoffset+i), ptn >> (count-1-i) & 1);
     117  	else
     118  	  bitset((bitoffset+i), ptn >> 2 & 1);
     119      }
     120    else switch (ptn)
     121      {
     122      case P_0R: case P_1R:
     123        assert(count > 0);
     124        bitset(bitoffset, ptn & 1);
     125        count--;
     126        bitoffset++;
     127      case P_R:
     128        for (; count > 0; count--, bitoffset++)
     129  	bitset(bitoffset, rand() & 1);
     130        break;
     131      case P_Ro:
     132        {
     133  	int op = 1;
     134  	assert(count > 0);
     135  	for (; count > 1; count--, bitoffset++)
     136  	  bitset(bitoffset, op ^= (rand() & 1));
     137  	bitset(bitoffset, op);
     138  	break;
     139        }
     140      case P_Rno:
     141        {
     142  	int op = 1;
     143  	assert(count > 0);
     144  	for (; count > 1; count--, bitoffset++)
     145  	{
     146  	  int r = rand() & 1;
     147  	  op &= r;
     148  	  bitset(bitoffset, r);
     149  	}
     150  	bitset(bitoffset, rand() & (op ^ 1));
     151  	break;
     152        }
     153  
     154      default:
     155        assert(0);
     156      }
     157  #undef bitset
     158  }
     159  
     160  static tocheck_t
     161  pattern(int negative, pattern_t exp, pattern_t mant)
     162  {
     163    union_t result;
     164  #if 0
     165    int i;
     166  #endif
     167  
     168    pattern_fill(negative ? P_O : P_Z, result.c, 0, 1);
     169    pattern_fill(exp, result.c, 1, ESIZE);
     170    pattern_fill(mant, result.c, ESIZE+1, MSIZE);
     171  #if 0
     172    printf("neg=%d exp=%02x mant=%02x: ", negative, exp, mant);
     173    for (i = 0; i < sizeof (tocheck_t); i++)
     174      printf("%02x", result.c[i]);
     175    printf("\n");
     176  #endif
     177    return result.tc;
     178  }
     179  
     180  /* Return the closest different tocheck_t to 'x' in the direction of
     181     'direction', or 'x' if there is no such value.  Assumes 'x' is not
     182     a NaN.  */
     183  static tocheck_t
     184  delta(tocheck_t x, int direction)
     185  {
     186    union_t xx;
     187    int i;
     188  
     189    xx.tc = x;
     190    if (xx.c[0] & 0x80)
     191      direction = -direction;
     192    if (direction == +1)
     193      {
     194        union_t tx;
     195        tx.tc = pattern(xx.c[0] >> 7, P_O, P_Z);
     196        if (memcmp (tx.c, xx.c, sizeof (tocheck_t)) == 0)
     197  	return x;
     198      }
     199    for (i = sizeof (tocheck_t)-1; i > 0; i--)
     200      {
     201        xx.c[i] += direction;
     202        if (xx.c[i] != (direction > 0 ? 0 : 0xff))
     203  	return xx.tc;
     204      }
     205    if (direction < 0 && (xx.c[0] & 0x7f) == 0)
     206      return pattern(~(xx.c[0] >> 7) & 1, P_Z, P_Z1);
     207    else
     208      {
     209        xx.c[0] += direction;
     210        return xx.tc;
     211      }
     212  }
     213  
     214  static int nerrors = 0;
     215  
     216  #ifdef FE_ALL_INVALID
     217  static const int all_exceptions = FE_ALL_INVALID | FE_ALL_EXCEPT;
     218  #else
     219  static const int all_exceptions = FE_ALL_EXCEPT;
     220  #endif
     221  
     222  static void
     223  check_result(int line, const char *rm, tocheck_t expected, tocheck_t actual)
     224  {
     225    if (memcmp (&expected, &actual, sizeof (tocheck_t)) != 0)
     226      {
     227        unsigned char *ex, *ac;
     228        size_t i;
     229  
     230        printf("%s:%d:round %s:result failed\n"
     231  	     " expected result 0x", __FILE__, line, rm);
     232        ex = (unsigned char *)&expected;
     233        ac = (unsigned char *)&actual;
     234        for (i = 0; i < sizeof (tocheck_t); i++)
     235  	printf("%02x", ex[i]);
     236        printf(" got 0x");
     237        for (i = 0; i < sizeof (tocheck_t); i++)
     238  	printf("%02x", ac[i]);
     239        printf("\n");
     240        nerrors++;
     241      }
     242  }
     243  
     244  static const struct {
     245    int except;
     246    const char *name;
     247  } excepts[] = {
     248  #define except_entry(ex) { ex, #ex } ,
     249  #ifdef FE_INEXACT
     250    except_entry(FE_INEXACT)
     251  #else
     252  # define FE_INEXACT 0
     253  #endif
     254  #ifdef FE_DIVBYZERO
     255    except_entry(FE_DIVBYZERO)
     256  #else
     257  # define FE_DIVBYZERO 0
     258  #endif
     259  #ifdef FE_UNDERFLOW
     260    except_entry(FE_UNDERFLOW)
     261  #else
     262  # define FE_UNDERFLOW 0
     263  #endif
     264  #ifdef FE_OVERFLOW
     265    except_entry(FE_OVERFLOW)
     266  #else
     267  # define FE_OVERFLOW 0
     268  #endif
     269  #ifdef FE_INVALID
     270    except_entry(FE_INVALID)
     271  #else
     272  # define FE_INVALID 0
     273  #endif
     274  #ifdef FE_INVALID_SNAN
     275    except_entry(FE_INVALID_SNAN)
     276  #else
     277  # define FE_INVALID_SNAN FE_INVALID
     278  #endif
     279  #ifdef FE_INVALID_ISI
     280    except_entry(FE_INVALID_ISI)
     281  #else
     282  # define FE_INVALID_ISI FE_INVALID
     283  #endif
     284  #ifdef FE_INVALID_IDI
     285    except_entry(FE_INVALID_IDI)
     286  #else
     287  # define FE_INVALID_IDI FE_INVALID
     288  #endif
     289  #ifdef FE_INVALID_ZDZ
     290    except_entry(FE_INVALID_ZDZ)
     291  #else
     292  # define FE_INVALID_ZDZ FE_INVALID
     293  #endif
     294  #ifdef FE_INVALID_COMPARE
     295    except_entry(FE_INVALID_COMPARE)
     296  #else
     297  # define FE_INVALID_COMPARE FE_INVALID
     298  #endif
     299  #ifdef FE_INVALID_SOFTWARE
     300    except_entry(FE_INVALID_SOFTWARE)
     301  #else
     302  # define FE_INVALID_SOFTWARE FE_INVALID
     303  #endif
     304  #ifdef FE_INVALID_SQRT
     305    except_entry(FE_INVALID_SQRT)
     306  #else
     307  # define FE_INVALID_SQRT FE_INVALID
     308  #endif
     309  #ifdef FE_INVALID_INTEGER_CONVERSION
     310    except_entry(FE_INVALID_INTEGER_CONVERSION)
     311  #else
     312  # define FE_INVALID_INTEGER_CONVERSION FE_INVALID
     313  #endif
     314  };
     315  
     316  static int excepts_missing = 0;
     317  
     318  static void
     319  check_excepts(int line, const char *rm, int expected, int actual)
     320  {
     321    if (expected & excepts_missing)
     322      expected = expected & ~excepts_missing | FE_INVALID_SNAN;
     323    if ((expected & all_exceptions) != actual)
     324      {
     325        size_t i;
     326        printf("%s:%d:round %s:exceptions failed\n"
     327  	     " expected exceptions ", __FILE__, line,rm);
     328        for (i = 0; i < sizeof (excepts) / sizeof (excepts[0]); i++)
     329  	if (expected & excepts[i].except)
     330  	  printf("%s ",excepts[i].name);
     331        if ((expected & all_exceptions) == 0)
     332  	printf("- ");
     333        printf("got");
     334        for (i = 0; i < sizeof (excepts) / sizeof (excepts[0]); i++)
     335  	if (actual & excepts[i].except)
     336  	  printf(" %s",excepts[i].name);
     337        if ((actual & all_exceptions) == 0)
     338  	printf("- ");
     339        printf(".\n");
     340        nerrors++;
     341      }
     342  }
     343  
     344  typedef enum {
     345    B_ADD, B_SUB, B_MUL, B_DIV, B_NEG, B_ABS, B_SQRT
     346  } op_t;
     347  typedef struct {
     348    int line;
     349    op_t op;
     350    int a_sgn;
     351    pattern_t a_exp, a_mant;
     352    int b_sgn;
     353    pattern_t b_exp, b_mant;
     354    int rmode;
     355    int excepts;
     356    int x_sgn;
     357    pattern_t x_exp, x_mant;
     358  } optest_t;
     359  static const optest_t optests[] = {
     360    /* Additions of zero.  */
     361    {__LINE__,B_ADD, 0,P_Z,P_Z, 0,P_Z,P_Z, R_ALL,0, 0,P_Z,P_Z },
     362    {__LINE__,B_ADD, 1,P_Z,P_Z, 0,P_Z,P_Z, R_ALL & ~R_DOWN,0, 0,P_Z,P_Z },
     363    {__LINE__,B_ADD, 1,P_Z,P_Z, 0,P_Z,P_Z, R_DOWN,0, 1,P_Z,P_Z },
     364    {__LINE__,B_ADD, 1,P_Z,P_Z, 1,P_Z,P_Z, R_ALL,0, 1,P_Z,P_Z },
     365  
     366    /* Additions with NaN.  */
     367    {__LINE__,B_ADD, 0,P_O,P_101Z, 0,P_Z,P_Z, R_ALL,0, 0,P_O,P_101Z },
     368    {__LINE__,B_ADD, 0,P_O,P_01Z, 0,P_Z,P_Z, R_ALL,
     369     FE_INVALID | FE_INVALID_SNAN, 0,P_O,P_11Z },
     370    {__LINE__,B_ADD, 0,P_O,P_Z, 0,P_O,P_0O, R_ALL,
     371     FE_INVALID | FE_INVALID_SNAN, 0,P_O,P_O },
     372    {__LINE__,B_ADD, 0,P_Z,P_Z, 0,P_O,P_11Z, R_ALL,0, 0,P_O,P_11Z },
     373    {__LINE__,B_ADD, 0,P_O,P_001Z, 0,P_O,P_001Z, R_ALL,
     374     FE_INVALID | FE_INVALID_SNAN, 0,P_O,P_101Z },
     375    {__LINE__,B_ADD, 0,P_O,P_1Z, 0,P_Z,P_Z, R_ALL,0, 0,P_O,P_1Z },
     376    {__LINE__,B_ADD, 0,P_0O,P_Z, 0,P_O,P_10O, R_ALL,0, 0,P_O,P_10O },
     377  
     378    /* Additions with infinity.  */
     379    {__LINE__,B_ADD, 0,P_O,P_Z, 0,P_Z,P_Z, R_ALL,0, 0,P_O,P_Z },
     380    {__LINE__,B_ADD, 0,P_O,P_Z, 1,P_Z,P_Z, R_ALL,0, 0,P_O,P_Z },
     381    {__LINE__,B_ADD, 1,P_O,P_Z, 0,P_Z,P_Z, R_ALL,0, 1,P_O,P_Z },
     382    {__LINE__,B_ADD, 1,P_O,P_Z, 1,P_Z,P_Z, R_ALL,0, 1,P_O,P_Z },
     383    {__LINE__,B_ADD, 0,P_O,P_Z, 0,P_O,P_Z, R_ALL,0, 0,P_O,P_Z },
     384    {__LINE__,B_ADD, 1,P_O,P_Z, 1,P_O,P_Z, R_ALL,0, 1,P_O,P_Z },
     385    {__LINE__,B_ADD, 0,P_O,P_Z, 1,P_O,P_Z, R_ALL,
     386     FE_INVALID | FE_INVALID_ISI, 0,P_O,P_1Z },
     387    {__LINE__,B_ADD, 1,P_O,P_Z, 0,P_O,P_Z, R_ALL,
     388     FE_INVALID | FE_INVALID_ISI, 0,P_O,P_1Z },
     389    {__LINE__,B_ADD, 0,P_O,P_Z, 0,P_0O,P_Z, R_ALL,0, 0,P_O,P_Z },
     390    {__LINE__,B_ADD, 1,P_O,P_Z, 0,P_0O,P_Z, R_ALL,0, 1,P_O,P_Z },
     391    {__LINE__,B_ADD, 0,P_O,P_Z, 1,P_0O,P_Z, R_ALL,0, 0,P_O,P_Z },
     392    {__LINE__,B_ADD, 1,P_O,P_Z, 1,P_0O,P_Z, R_ALL,0, 1,P_O,P_Z },
     393  
     394    /* Overflow (and zero).  */
     395    {__LINE__,B_ADD, 0,P_O0,P_Z, 0,P_O0,P_Z, R_NEAREST | R_UP,
     396     FE_INEXACT | FE_OVERFLOW, 0,P_O,P_Z },
     397    {__LINE__,B_ADD, 0,P_O0,P_Z, 0,P_O0,P_Z, R_ZERO | R_DOWN,
     398     FE_INEXACT | FE_OVERFLOW, 0,P_O0,P_O },
     399    {__LINE__,B_ADD, 1,P_O0,P_Z, 1,P_O0,P_Z, R_NEAREST | R_DOWN,
     400     FE_INEXACT | FE_OVERFLOW, 1,P_O,P_Z },
     401    {__LINE__,B_ADD, 1,P_O0,P_Z, 1,P_O0,P_Z, R_ZERO | R_UP,
     402     FE_INEXACT | FE_OVERFLOW, 1,P_O0,P_O },
     403    {__LINE__,B_ADD, 0,P_O0,P_Z, 1,P_O0,P_Z, R_ALL & ~R_DOWN,
     404     0, 0,P_Z,P_Z },
     405    {__LINE__,B_ADD, 0,P_O0,P_Z, 1,P_O0,P_Z, R_DOWN,
     406     0, 1,P_Z,P_Z },
     407  
     408    /* Negation.  */
     409    {__LINE__,B_NEG, 0,P_Z,P_Z,   0,0,0, R_ALL, 0, 1,P_Z,P_Z },
     410    {__LINE__,B_NEG, 1,P_Z,P_Z,   0,0,0, R_ALL, 0, 0,P_Z,P_Z },
     411    {__LINE__,B_NEG, 0,P_O,P_Z,   0,0,0, R_ALL, 0, 1,P_O,P_Z },
     412    {__LINE__,B_NEG, 1,P_O,P_Z,   0,0,0, R_ALL, 0, 0,P_O,P_Z },
     413    {__LINE__,B_NEG, 0,P_O,P_1Z,  0,0,0, R_ALL, 0, 1,P_O,P_1Z },
     414    {__LINE__,B_NEG, 1,P_O,P_1Z,  0,0,0, R_ALL, 0, 0,P_O,P_1Z },
     415    {__LINE__,B_NEG, 0,P_O,P_01Z, 0,0,0, R_ALL, 0, 1,P_O,P_01Z },
     416    {__LINE__,B_NEG, 1,P_O,P_01Z, 0,0,0, R_ALL, 0, 0,P_O,P_01Z },
     417    {__LINE__,B_NEG, 0,P_1Z,P_1Z1, 0,0,0, R_ALL, 0, 1,P_1Z,P_1Z1 },
     418    {__LINE__,B_NEG, 1,P_1Z,P_1Z1, 0,0,0, R_ALL, 0, 0,P_1Z,P_1Z1 },
     419    {__LINE__,B_NEG, 0,P_Z,P_Z1,  0,0,0, R_ALL, 0, 1,P_Z,P_Z1 },
     420    {__LINE__,B_NEG, 1,P_Z,P_Z1,  0,0,0, R_ALL, 0, 0,P_Z,P_Z1 },
     421  
     422    /* Absolute value.  */
     423    {__LINE__,B_ABS, 0,P_Z,P_Z,   0,0,0, R_ALL, 0, 0,P_Z,P_Z },
     424    {__LINE__,B_ABS, 1,P_Z,P_Z,   0,0,0, R_ALL, 0, 0,P_Z,P_Z },
     425    {__LINE__,B_ABS, 0,P_O,P_Z,   0,0,0, R_ALL, 0, 0,P_O,P_Z },
     426    {__LINE__,B_ABS, 1,P_O,P_Z,   0,0,0, R_ALL, 0, 0,P_O,P_Z },
     427    {__LINE__,B_ABS, 0,P_O,P_1Z,  0,0,0, R_ALL, 0, 0,P_O,P_1Z },
     428    {__LINE__,B_ABS, 1,P_O,P_1Z,  0,0,0, R_ALL, 0, 0,P_O,P_1Z },
     429    {__LINE__,B_ABS, 0,P_O,P_01Z, 0,0,0, R_ALL, 0, 0,P_O,P_01Z },
     430    {__LINE__,B_ABS, 1,P_O,P_01Z, 0,0,0, R_ALL, 0, 0,P_O,P_01Z },
     431    {__LINE__,B_ABS, 0,P_1Z,P_1Z1, 0,0,0, R_ALL, 0, 0,P_1Z,P_1Z1 },
     432    {__LINE__,B_ABS, 1,P_1Z,P_1Z1, 0,0,0, R_ALL, 0, 0,P_1Z,P_1Z1 },
     433    {__LINE__,B_ABS, 0,P_Z,P_Z1,  0,0,0, R_ALL, 0, 0,P_Z,P_Z1 },
     434    {__LINE__,B_ABS, 1,P_Z,P_Z1,  0,0,0, R_ALL, 0, 0,P_Z,P_Z1 },
     435  
     436    /* Square root.  */
     437    {__LINE__,B_SQRT, 0,P_Z,P_Z,   0,0,0, R_ALL, 0, 0,P_Z,P_Z },
     438    {__LINE__,B_SQRT, 1,P_Z,P_Z,   0,0,0, R_ALL, 0, 1,P_Z,P_Z },
     439    {__LINE__,B_SQRT, 0,P_O,P_1Z,  0,0,0, R_ALL, 0, 0,P_O,P_1Z },
     440    {__LINE__,B_SQRT, 1,P_O,P_1Z,  0,0,0, R_ALL, 0, 1,P_O,P_1Z },
     441    {__LINE__,B_SQRT, 0,P_O,P_01Z, 0,0,0, R_ALL,
     442     FE_INVALID | FE_INVALID_SNAN, 0,P_O,P_11Z },
     443    {__LINE__,B_SQRT, 1,P_O,P_01Z, 0,0,0, R_ALL,
     444     FE_INVALID | FE_INVALID_SNAN, 1,P_O,P_11Z },
     445  
     446    {__LINE__,B_SQRT, 0,P_O,P_Z,   0,0,0, R_ALL, 0, 0,P_O,P_Z },
     447    {__LINE__,B_SQRT, 0,P_0O,P_Z,  0,0,0, R_ALL, 0, 0,P_0O,P_Z },
     448  
     449    {__LINE__,B_SQRT, 1,P_O,P_Z,   0,0,0, R_ALL,
     450     FE_INVALID | FE_INVALID_SQRT, 0,P_O,P_1Z },
     451    {__LINE__,B_SQRT, 1,P_1Z,P_1Z1, 0,0,0, R_ALL,
     452     FE_INVALID | FE_INVALID_SQRT, 0,P_O,P_1Z },
     453    {__LINE__,B_SQRT, 1,P_Z,P_Z1,  0,0,0, R_ALL,
     454     FE_INVALID | FE_INVALID_SQRT, 0,P_O,P_1Z },
     455  
     456  };
     457  
     458  static void
     459  check_op(void)
     460  {
     461    size_t i;
     462    int j;
     463    tocheck_t r, a, b, x;
     464    int raised;
     465  
     466    for (i = 0; i < sizeof (optests) / sizeof (optests[0]); i++)
     467      {
     468        a = pattern(optests[i].a_sgn, optests[i].a_exp,
     469  		  optests[i].a_mant);
     470        b = pattern(optests[i].b_sgn, optests[i].b_exp,
     471  		  optests[i].b_mant);
     472        x = pattern(optests[i].x_sgn, optests[i].x_exp,
     473  		  optests[i].x_mant);
     474        for (j = 0; j < 4; j++)
     475  	if (optests[i].rmode & 1<<j)
     476  	  {
     477  	    fesetenv(rmodes+j);
     478  	    switch (optests[i].op)
     479  	      {
     480  	      case B_ADD: r = a + b; break;
     481  	      case B_SUB: r = a - b; break;
     482  	      case B_MUL: r = a * b; break;
     483  	      case B_DIV: r = a / b; break;
     484  	      case B_NEG: r = -a; break;
     485  	      case B_ABS: r = FUNC(fabs)(a); break;
     486  	      case B_SQRT: r = FUNC(sqrt)(a); break;
     487  	      }
     488  	    raised = fetestexcept(all_exceptions);
     489  	    check_result(optests[i].line,rmnames[j],x,r);
     490  	    check_excepts(optests[i].line,rmnames[j],
     491  			  optests[i].excepts,raised);
     492  	  }
     493      }
     494  }
     495  
     496  static void
     497  fail_xr(int line, const char *rm, tocheck_t x, tocheck_t r, tocheck_t xx,
     498  	int xflag)
     499  {
     500    size_t i;
     501    unsigned char *cx, *cr, *cxx;
     502  
     503    printf("%s:%d:round %s:fail\n with x=0x", __FILE__, line,rm);
     504    cx = (unsigned char *)&x;
     505    cr = (unsigned char *)&r;
     506    cxx = (unsigned char *)&xx;
     507    for (i = 0; i < sizeof (tocheck_t); i++)
     508      printf("%02x", cx[i]);
     509    printf(" r=0x");
     510    for (i = 0; i < sizeof (tocheck_t); i++)
     511      printf("%02x", cr[i]);
     512    printf(" xx=0x");
     513    for (i = 0; i < sizeof (tocheck_t); i++)
     514      printf("%02x", cxx[i]);
     515    printf(" inexact=%d\n", xflag != 0);
     516    nerrors++;
     517  }
     518  
     519  static void
     520  check_sqrt(tocheck_t a)
     521  {
     522    int j;
     523    tocheck_t r0, r1, r2, x0, x1, x2;
     524    int raised = 0;
     525    int ok;
     526  
     527    for (j = 0; j < 4; j++)
     528      {
     529        int excepts;
     530  
     531        fesetenv(rmodes+j);
     532        r1 = FUNC(sqrt)(a);
     533        excepts = fetestexcept(all_exceptions);
     534        fesetenv(FE_DFL_ENV);
     535        raised |= excepts & ~FE_INEXACT;
     536        x1 = r1 * r1 - a;
     537        if (excepts & FE_INEXACT)
     538  	{
     539  	  r0 = delta(r1,-1); r2 = delta(r1,1);
     540  	  switch (1 << j)
     541  	    {
     542  	    case R_NEAREST:
     543  	      x0 = r0 * r0 - a; x2 = r2 * r2 - a;
     544  	      ok = fabs(x0) >= fabs(x1) && fabs(x1) <= fabs(x2);
     545  	      break;
     546  	    case R_ZERO:  case R_DOWN:
     547  	      x2 = r2 * r2 - a;
     548  	      ok = x1 <= 0 && x2 >= 0;
     549  	      break;
     550  	    case R_UP:
     551  	      x0 = r0 * r0 - a;
     552  	      ok = x1 >= 0 && x0 <= 0;
     553  	      break;
     554  	    default:
     555  	      assert(0);
     556  	    }
     557  	}
     558        else
     559  	ok = x1 == 0;
     560        if (!ok)
     561  	fail_xr(__LINE__,rmnames[j],a,r1,x1,excepts&FE_INEXACT);
     562      }
     563    check_excepts(__LINE__,"all",0,raised);
     564  }
     565  
     566  int main(int argc, char **argv)
     567  {
     568    int i;
     569  
     570    _LIB_VERSION = _IEEE_;
     571  
     572    /* Set up environments for rounding modes.  */
     573    fesetenv(FE_DFL_ENV);
     574    fesetround(FE_TONEAREST);
     575    fegetenv(rmodes+0);
     576    fesetround(FE_TOWARDZERO);
     577    fegetenv(rmodes+1);
     578    fesetround(FE_UPWARD);
     579    fegetenv(rmodes+2);
     580    fesetround(FE_DOWNWARD);
     581    fegetenv(rmodes+3);
     582  
     583  #if defined(FE_INVALID_SOFTWARE) || defined(FE_INVALID_SQRT)
     584    /* There's this really stupid feature of the 601... */
     585    fesetenv(FE_DFL_ENV);
     586    feraiseexcept(FE_INVALID_SOFTWARE);
     587    if (!fetestexcept(FE_INVALID_SOFTWARE))
     588      excepts_missing |= FE_INVALID_SOFTWARE;
     589    fesetenv(FE_DFL_ENV);
     590    feraiseexcept(FE_INVALID_SQRT);
     591    if (!fetestexcept(FE_INVALID_SQRT))
     592      excepts_missing |= FE_INVALID_SQRT;
     593  #endif
     594  
     595    check_op();
     596    for (i = 0; i < 100000; i++)
     597      check_sqrt(pattern(0, P_Rno, P_R));
     598    for (i = 0; i < 100; i++)
     599      check_sqrt(pattern(0, P_Z, P_R));
     600    check_sqrt(pattern(0,P_Z,P_Z1));
     601  
     602    printf("%d errors.\n", nerrors);
     603    return nerrors == 0 ? 0 : 1;
     604  }