(root)/
glibc-2.38/
math/
test-fenv.c
       1  /* Copyright (C) 1997-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  /* Tests for ISO C99 7.6: Floating-point environment  */
      19  
      20  #ifndef _GNU_SOURCE
      21  # define _GNU_SOURCE
      22  #endif
      23  
      24  #include <complex.h>
      25  #include <math.h>
      26  #include <float.h>
      27  #include <fenv.h>
      28  
      29  #include <errno.h>
      30  #include <signal.h>
      31  #include <stdlib.h>
      32  #include <stdio.h>
      33  #include <string.h>
      34  #include <unistd.h>
      35  #include <sys/wait.h>
      36  #include <sys/resource.h>
      37  #include <math-tests.h>
      38  
      39  /*
      40    Since not all architectures might define all exceptions, we define
      41    a private set and map accordingly.
      42  */
      43  #define NO_EXC 0
      44  #define INEXACT_EXC 0x1
      45  #define DIVBYZERO_EXC 0x2
      46  #define UNDERFLOW_EXC 0x04
      47  #define OVERFLOW_EXC 0x08
      48  #define INVALID_EXC 0x10
      49  #define ALL_EXC \
      50          (INEXACT_EXC | DIVBYZERO_EXC | UNDERFLOW_EXC | OVERFLOW_EXC \
      51           | INVALID_EXC)
      52  
      53  static int count_errors;
      54  
      55  #if FE_ALL_EXCEPT
      56  /* Test whether a given exception was raised.  */
      57  static void
      58  test_single_exception (short int exception,
      59                         short int exc_flag,
      60                         fexcept_t fe_flag,
      61                         const char *flag_name)
      62  {
      63    if (exception & exc_flag)
      64      {
      65        if (fetestexcept (fe_flag))
      66          printf ("  Pass: Exception \"%s\" is set\n", flag_name);
      67        else
      68          {
      69            printf ("  Fail: Exception \"%s\" is not set\n", flag_name);
      70            ++count_errors;
      71          }
      72      }
      73    else
      74      {
      75        if (fetestexcept (fe_flag))
      76          {
      77            printf ("  Fail: Exception \"%s\" is set\n", flag_name);
      78            ++count_errors;
      79          }
      80        else
      81          {
      82            printf ("  Pass: Exception \"%s\" is not set\n", flag_name);
      83          }
      84      }
      85  }
      86  #endif
      87  
      88  static void
      89  test_exceptions (const char *test_name, short int exception,
      90  		 int ignore_inexact)
      91  {
      92    printf ("Test: %s\n", test_name);
      93  #ifdef FE_DIVBYZERO
      94    test_single_exception (exception, DIVBYZERO_EXC, FE_DIVBYZERO,
      95                           "DIVBYZERO");
      96  #endif
      97  #ifdef FE_INVALID
      98    test_single_exception (exception, INVALID_EXC, FE_INVALID,
      99                           "INVALID");
     100  #endif
     101  #ifdef FE_INEXACT
     102    if (!ignore_inexact)
     103      test_single_exception (exception, INEXACT_EXC, FE_INEXACT,
     104  			   "INEXACT");
     105  #endif
     106  #ifdef FE_UNDERFLOW
     107    test_single_exception (exception, UNDERFLOW_EXC, FE_UNDERFLOW,
     108                           "UNDERFLOW");
     109  #endif
     110  #ifdef FE_OVERFLOW
     111    test_single_exception (exception, OVERFLOW_EXC, FE_OVERFLOW,
     112                           "OVERFLOW");
     113  #endif
     114  }
     115  
     116  static void
     117  print_rounding (int rounding)
     118  {
     119  
     120    switch (rounding)
     121      {
     122  #ifdef FE_TONEAREST
     123      case FE_TONEAREST:
     124        printf ("TONEAREST");
     125        break;
     126  #endif
     127  #ifdef FE_UPWARD
     128      case FE_UPWARD:
     129        printf ("UPWARD");
     130        break;
     131  #endif
     132  #ifdef FE_DOWNWARD
     133      case FE_DOWNWARD:
     134        printf ("DOWNWARD");
     135        break;
     136  #endif
     137  #ifdef FE_TOWARDZERO
     138      case FE_TOWARDZERO:
     139        printf ("TOWARDZERO");
     140        break;
     141  #endif
     142      }
     143    printf (".\n");
     144  }
     145  
     146  
     147  static void
     148  test_rounding (const char *test_name, int rounding_mode)
     149  {
     150    int curr_rounding = fegetround ();
     151  
     152    printf ("Test: %s\n", test_name);
     153    if (curr_rounding == rounding_mode)
     154      {
     155        printf ("  Pass: Rounding mode is ");
     156        print_rounding (curr_rounding);
     157      }
     158    else
     159      {
     160        ++count_errors;
     161        printf ("  Fail: Rounding mode is ");
     162        print_rounding (curr_rounding);
     163      }
     164  }
     165  
     166  
     167  #if FE_ALL_EXCEPT
     168  static void
     169  set_single_exc (const char *test_name, int fe_exc, fexcept_t exception)
     170  {
     171    char str[200];
     172    /* The standard allows the inexact exception to be set together with the
     173       underflow and overflow exceptions.  So ignore the inexact flag if the
     174       others are raised.  */
     175    int ignore_inexact = (fe_exc & (UNDERFLOW_EXC | OVERFLOW_EXC)) != 0;
     176  
     177    strcpy (str, test_name);
     178    strcat (str, ": set flag, with rest not set");
     179    feclearexcept (FE_ALL_EXCEPT);
     180    feraiseexcept (exception);
     181    test_exceptions (str, fe_exc, ignore_inexact);
     182  
     183    strcpy (str, test_name);
     184    strcat (str, ": clear flag, rest also unset");
     185    feclearexcept (exception);
     186    test_exceptions (str, NO_EXC, ignore_inexact);
     187  
     188    strcpy (str, test_name);
     189    strcat (str, ": set flag, with rest set");
     190    feraiseexcept (FE_ALL_EXCEPT ^ exception);
     191    feraiseexcept (exception);
     192    test_exceptions (str, ALL_EXC, 0);
     193  
     194    strcpy (str, test_name);
     195    strcat (str, ": clear flag, leave rest set");
     196    feclearexcept (exception);
     197    test_exceptions (str, ALL_EXC ^ fe_exc, 0);
     198  }
     199  #endif
     200  
     201  static void
     202  fe_tests (void)
     203  {
     204    /* clear all exceptions and test if all are cleared */
     205    feclearexcept (FE_ALL_EXCEPT);
     206    test_exceptions ("feclearexcept (FE_ALL_EXCEPT) clears all exceptions",
     207                     NO_EXC, 0);
     208  
     209    /* Skip further tests here if exceptions not supported.  */
     210    if (!EXCEPTION_TESTS (float) && FE_ALL_EXCEPT != 0)
     211      return;
     212    /* raise all exceptions and test if all are raised */
     213    feraiseexcept (FE_ALL_EXCEPT);
     214    test_exceptions ("feraiseexcept (FE_ALL_EXCEPT) raises all exceptions",
     215                     ALL_EXC, 0);
     216    feclearexcept (FE_ALL_EXCEPT);
     217  
     218  #ifdef FE_DIVBYZERO
     219    set_single_exc ("Set/Clear FE_DIVBYZERO", DIVBYZERO_EXC, FE_DIVBYZERO);
     220  #endif
     221  #ifdef FE_INVALID
     222    set_single_exc ("Set/Clear FE_INVALID", INVALID_EXC, FE_INVALID);
     223  #endif
     224  #ifdef FE_INEXACT
     225    set_single_exc ("Set/Clear FE_INEXACT", INEXACT_EXC, FE_INEXACT);
     226  #endif
     227  #ifdef FE_UNDERFLOW
     228    set_single_exc ("Set/Clear FE_UNDERFLOW", UNDERFLOW_EXC, FE_UNDERFLOW);
     229  #endif
     230  #ifdef FE_OVERFLOW
     231    set_single_exc ("Set/Clear FE_OVERFLOW", OVERFLOW_EXC, FE_OVERFLOW);
     232  #endif
     233  }
     234  
     235  #if FE_ALL_EXCEPT
     236  /* Test that program aborts with no masked interrupts */
     237  static void
     238  feenv_nomask_test (const char *flag_name, int fe_exc)
     239  {
     240  # if defined FE_NOMASK_ENV
     241    int status;
     242    pid_t pid;
     243  
     244    if (!EXCEPTION_ENABLE_SUPPORTED (FE_ALL_EXCEPT)
     245        && fesetenv (FE_NOMASK_ENV) != 0)
     246      {
     247        printf ("Test: not testing FE_NOMASK_ENV, it isn't implemented.\n");
     248        return;
     249      }
     250  
     251    printf ("Test: after fesetenv (FE_NOMASK_ENV) processes will abort\n");
     252    printf ("      when feraiseexcept (%s) is called.\n", flag_name);
     253    pid = fork ();
     254    if (pid == 0)
     255      {
     256  #  ifdef RLIMIT_CORE
     257        /* Try to avoid dumping core.  */
     258        struct rlimit core_limit;
     259        core_limit.rlim_cur = 0;
     260        core_limit.rlim_max = 0;
     261        setrlimit (RLIMIT_CORE, &core_limit);
     262  #  endif
     263  
     264        fesetenv (FE_NOMASK_ENV);
     265        feraiseexcept (fe_exc);
     266        exit (2);
     267      }
     268    else if (pid < 0)
     269      {
     270        if (errno != ENOSYS)
     271  	{
     272  	  printf ("  Fail: Could not fork.\n");
     273  	  ++count_errors;
     274  	}
     275        else
     276  	printf ("  `fork' not implemented, test ignored.\n");
     277      }
     278    else {
     279      if (waitpid (pid, &status, 0) != pid)
     280        {
     281  	printf ("  Fail: waitpid call failed.\n");
     282  	++count_errors;
     283        }
     284      else if (WIFSIGNALED (status) && WTERMSIG (status) == SIGFPE)
     285        printf ("  Pass: Process received SIGFPE.\n");
     286      else
     287        {
     288  	printf ("  Fail: Process didn't receive signal and exited with status %d.\n",
     289  		status);
     290  	++count_errors;
     291        }
     292    }
     293  # endif
     294  }
     295  
     296  /* Test that program doesn't abort with default environment */
     297  static void
     298  feenv_mask_test (const char *flag_name, int fe_exc)
     299  {
     300    int status;
     301    pid_t pid;
     302  
     303    printf ("Test: after fesetenv (FE_DFL_ENV) processes will not abort\n");
     304    printf ("      when feraiseexcept (%s) is called.\n", flag_name);
     305    pid = fork ();
     306    if (pid == 0)
     307      {
     308  #ifdef RLIMIT_CORE
     309        /* Try to avoid dumping core.  */
     310        struct rlimit core_limit;
     311        core_limit.rlim_cur = 0;
     312        core_limit.rlim_max = 0;
     313        setrlimit (RLIMIT_CORE, &core_limit);
     314  #endif
     315  
     316        fesetenv (FE_DFL_ENV);
     317        feraiseexcept (fe_exc);
     318        exit (2);
     319      }
     320    else if (pid < 0)
     321      {
     322        if (errno != ENOSYS)
     323  	{
     324  	  printf ("  Fail: Could not fork.\n");
     325  	  ++count_errors;
     326  	}
     327        else
     328  	printf ("  `fork' not implemented, test ignored.\n");
     329      }
     330    else {
     331      if (waitpid (pid, &status, 0) != pid)
     332        {
     333  	printf ("  Fail: waitpid call failed.\n");
     334  	++count_errors;
     335        }
     336      else if (WIFEXITED (status) && WEXITSTATUS (status) == 2)
     337        printf ("  Pass: Process exited normally.\n");
     338      else
     339        {
     340  	printf ("  Fail: Process exited abnormally with status %d.\n",
     341  		status);
     342  	++count_errors;
     343        }
     344    }
     345  }
     346  
     347  /* Test that program aborts with no masked interrupts */
     348  static void
     349  feexcp_nomask_test (const char *flag_name, int fe_exc)
     350  {
     351    int status;
     352    pid_t pid;
     353  
     354    if (!EXCEPTION_ENABLE_SUPPORTED (fe_exc) && feenableexcept (fe_exc) == -1)
     355      {
     356        printf ("Test: not testing feenableexcept, it isn't implemented.\n");
     357        return;
     358      }
     359  
     360    printf ("Test: after feenableexcept (%s) processes will abort\n",
     361  	  flag_name);
     362    printf ("      when feraiseexcept (%s) is called.\n", flag_name);
     363    pid = fork ();
     364    if (pid == 0)
     365      {
     366  #ifdef RLIMIT_CORE
     367        /* Try to avoid dumping core.  */
     368        struct rlimit core_limit;
     369        core_limit.rlim_cur = 0;
     370        core_limit.rlim_max = 0;
     371        setrlimit (RLIMIT_CORE, &core_limit);
     372  #endif
     373  
     374        fedisableexcept (FE_ALL_EXCEPT);
     375        feenableexcept (fe_exc);
     376        feraiseexcept (fe_exc);
     377        exit (2);
     378      }
     379    else if (pid < 0)
     380      {
     381        if (errno != ENOSYS)
     382  	{
     383  	  printf ("  Fail: Could not fork.\n");
     384  	  ++count_errors;
     385  	}
     386        else
     387  	printf ("  `fork' not implemented, test ignored.\n");
     388      }
     389    else {
     390      if (waitpid (pid, &status, 0) != pid)
     391        {
     392  	printf ("  Fail: waitpid call failed.\n");
     393  	++count_errors;
     394        }
     395      else if (WIFSIGNALED (status) && WTERMSIG (status) == SIGFPE)
     396        printf ("  Pass: Process received SIGFPE.\n");
     397      else
     398        {
     399  	printf ("  Fail: Process didn't receive signal and exited with status %d.\n",
     400  		status);
     401  	++count_errors;
     402        }
     403    }
     404  }
     405  
     406  /* Test that program doesn't abort with exception.  */
     407  static void
     408  feexcp_mask_test (const char *flag_name, int fe_exc)
     409  {
     410    int status;
     411    int exception;
     412    pid_t pid;
     413  
     414    printf ("Test: after fedisableexcept (%s) processes will not abort\n",
     415  	  flag_name);
     416    printf ("      when feraiseexcept (%s) is called.\n", flag_name);
     417    pid = fork ();
     418    if (pid == 0)
     419      {
     420  #ifdef RLIMIT_CORE
     421        /* Try to avoid dumping core.  */
     422        struct rlimit core_limit;
     423        core_limit.rlim_cur = 0;
     424        core_limit.rlim_max = 0;
     425        setrlimit (RLIMIT_CORE, &core_limit);
     426  #endif
     427        feenableexcept (FE_ALL_EXCEPT);
     428        exception = fe_exc;
     429  #ifdef FE_INEXACT
     430        /* The standard allows the inexact exception to be set together with the
     431  	 underflow and overflow exceptions.  So add FE_INEXACT to the set of
     432  	 exceptions to be disabled if we will be raising underflow or
     433  	 overflow.  */
     434  # ifdef FE_OVERFLOW
     435        if (fe_exc & FE_OVERFLOW)
     436  	exception |= FE_INEXACT;
     437  # endif
     438  # ifdef FE_UNDERFLOW
     439        if (fe_exc & FE_UNDERFLOW)
     440  	exception |= FE_INEXACT;
     441  # endif
     442  #endif
     443        fedisableexcept (exception);
     444        feraiseexcept (fe_exc);
     445        exit (2);
     446      }
     447    else if (pid < 0)
     448      {
     449        if (errno != ENOSYS)
     450  	{
     451  	  printf ("  Fail: Could not fork.\n");
     452  	  ++count_errors;
     453  	}
     454        else
     455  	printf ("  `fork' not implemented, test ignored.\n");
     456      }
     457    else {
     458      if (waitpid (pid, &status, 0) != pid)
     459        {
     460  	printf ("  Fail: waitpid call failed.\n");
     461  	++count_errors;
     462        }
     463      else if (WIFEXITED (status) && WEXITSTATUS (status) == 2)
     464        printf ("  Pass: Process exited normally.\n");
     465      else
     466        {
     467  	printf ("  Fail: Process exited abnormally with status %d.\n",
     468  		status);
     469  	++count_errors;
     470        }
     471    }
     472  }
     473  
     474  
     475  /* Tests for feenableexcept/fedisableexcept/fegetexcept.  */
     476  static void
     477  feenable_test (const char *flag_name, int fe_exc)
     478  {
     479    int excepts;
     480  
     481    printf ("Tests for feenableexcepts etc. with flag %s\n", flag_name);
     482  
     483    /* First disable all exceptions.  */
     484    if (fedisableexcept (FE_ALL_EXCEPT) == -1)
     485      {
     486        printf ("Test: fedisableexcept (FE_ALL_EXCEPT) failed\n");
     487        ++count_errors;
     488        /* If this fails, the other tests don't make sense.  */
     489        return;
     490      }
     491    excepts = fegetexcept ();
     492    if (excepts != 0)
     493      {
     494        printf ("Test: fegetexcept (%s) failed, return should be 0, is %d\n",
     495  	      flag_name, excepts);
     496        ++count_errors;
     497      }
     498    excepts = feenableexcept (fe_exc);
     499    if (!EXCEPTION_ENABLE_SUPPORTED (fe_exc) && excepts == -1)
     500      {
     501        printf ("Test: not testing feenableexcept, it isn't implemented.\n");
     502        return;
     503      }
     504    if (excepts == -1)
     505      {
     506        printf ("Test: feenableexcept (%s) failed\n", flag_name);
     507        ++count_errors;
     508        return;
     509      }
     510    if (excepts != 0)
     511      {
     512        printf ("Test: feenableexcept (%s) failed, return should be 0, is %x\n",
     513  	      flag_name, excepts);
     514        ++count_errors;
     515      }
     516  
     517    excepts = fegetexcept ();
     518    if (excepts != fe_exc)
     519      {
     520        printf ("Test: fegetexcept (%s) failed, return should be 0x%x, is 0x%x\n",
     521  	      flag_name, fe_exc, excepts);
     522        ++count_errors;
     523      }
     524  
     525    /* And now disable the exception again.  */
     526    excepts = fedisableexcept (fe_exc);
     527    if (excepts == -1)
     528      {
     529        printf ("Test: fedisableexcept (%s) failed\n", flag_name);
     530        ++count_errors;
     531        return;
     532      }
     533    if (excepts != fe_exc)
     534      {
     535        printf ("Test: fedisableexcept (%s) failed, return should be 0x%x, is 0x%x\n",
     536  	      flag_name, fe_exc, excepts);
     537        ++count_errors;
     538      }
     539  
     540    excepts = fegetexcept ();
     541    if (excepts != 0)
     542      {
     543        printf ("Test: fegetexcept (%s) failed, return should be 0, is 0x%x\n",
     544  	      flag_name, excepts);
     545        ++count_errors;
     546      }
     547  
     548    /* Now the other way round: Enable all exceptions and disable just this one.  */
     549    if (feenableexcept (FE_ALL_EXCEPT) == -1)
     550      {
     551        printf ("Test: feenableexcept (FE_ALL_EXCEPT) failed\n");
     552        ++count_errors;
     553        /* If this fails, the other tests don't make sense.  */
     554        return;
     555      }
     556  
     557    excepts = fegetexcept ();
     558    if (excepts != FE_ALL_EXCEPT)
     559      {
     560        printf ("Test: fegetexcept (%s) failed, return should be 0x%x, is 0x%x\n",
     561  	      flag_name, FE_ALL_EXCEPT, excepts);
     562        ++count_errors;
     563      }
     564  
     565    excepts = fedisableexcept (fe_exc);
     566    if (excepts == -1)
     567      {
     568        printf ("Test: fedisableexcept (%s) failed\n", flag_name);
     569        ++count_errors;
     570        return;
     571      }
     572    if (excepts != FE_ALL_EXCEPT)
     573      {
     574        printf ("Test: fedisableexcept (%s) failed, return should be 0, is 0x%x\n",
     575  	      flag_name, excepts);
     576        ++count_errors;
     577      }
     578  
     579    excepts = fegetexcept ();
     580    if (excepts != (FE_ALL_EXCEPT & ~fe_exc))
     581      {
     582        printf ("Test: fegetexcept (%s) failed, return should be 0x%x, is 0x%x\n",
     583  	      flag_name, (FE_ALL_EXCEPT & ~fe_exc), excepts);
     584        ++count_errors;
     585      }
     586  
     587    /* And now enable the exception again.  */
     588    excepts = feenableexcept (fe_exc);
     589    if (excepts == -1)
     590      {
     591        printf ("Test: feenableexcept (%s) failed\n", flag_name);
     592        ++count_errors;
     593        return;
     594      }
     595    if (excepts != (FE_ALL_EXCEPT & ~fe_exc))
     596      {
     597        printf ("Test: feenableexcept (%s) failed, return should be 0, is 0x%x\n",
     598  	      flag_name, excepts);
     599        ++count_errors;
     600      }
     601  
     602    excepts = fegetexcept ();
     603    if (excepts != FE_ALL_EXCEPT)
     604      {
     605        printf ("Test: fegetexcept (%s) failed, return should be 0x%x, is 0x%x\n",
     606  	      flag_name, FE_ALL_EXCEPT, excepts);
     607        ++count_errors;
     608      }
     609    feexcp_nomask_test (flag_name, fe_exc);
     610    feexcp_mask_test (flag_name, fe_exc);
     611  
     612  }
     613  
     614  
     615  static void
     616  fe_single_test (const char *flag_name, int fe_exc)
     617  {
     618    feenv_nomask_test (flag_name, fe_exc);
     619    feenv_mask_test (flag_name, fe_exc);
     620    feenable_test (flag_name, fe_exc);
     621  }
     622  #endif
     623  
     624  
     625  static void
     626  feenv_tests (void)
     627  {
     628    /* We might have some exceptions still set.  */
     629    feclearexcept (FE_ALL_EXCEPT);
     630  
     631  #ifdef FE_DIVBYZERO
     632    fe_single_test ("FE_DIVBYZERO", FE_DIVBYZERO);
     633  #endif
     634  #ifdef FE_INVALID
     635    fe_single_test ("FE_INVALID", FE_INVALID);
     636  #endif
     637  #ifdef FE_INEXACT
     638    fe_single_test ("FE_INEXACT", FE_INEXACT);
     639  #endif
     640  #ifdef FE_UNDERFLOW
     641    fe_single_test ("FE_UNDERFLOW", FE_UNDERFLOW);
     642  #endif
     643  #ifdef FE_OVERFLOW
     644    fe_single_test ("FE_OVERFLOW", FE_OVERFLOW);
     645  #endif
     646    fesetenv (FE_DFL_ENV);
     647  }
     648  
     649  
     650  static void
     651  feholdexcept_tests (void)
     652  {
     653    fenv_t saved, saved2;
     654    int res;
     655  
     656    feclearexcept (FE_ALL_EXCEPT);
     657    fedisableexcept (FE_ALL_EXCEPT);
     658  #ifdef FE_DIVBYZERO
     659    feraiseexcept (FE_DIVBYZERO);
     660  #endif
     661    if (EXCEPTION_TESTS (float))
     662      test_exceptions ("feholdexcept_tests FE_DIVBYZERO test",
     663  		     DIVBYZERO_EXC, 0);
     664    res = feholdexcept (&saved);
     665    if (res != 0)
     666      {
     667        printf ("feholdexcept failed: %d\n", res);
     668        ++count_errors;
     669      }
     670  #if defined FE_TONEAREST && defined FE_TOWARDZERO
     671    res = fesetround (FE_TOWARDZERO);
     672    if (res != 0 && ROUNDING_TESTS (float, FE_TOWARDZERO))
     673      {
     674        printf ("fesetround failed: %d\n", res);
     675        ++count_errors;
     676      }
     677  #endif
     678    test_exceptions ("feholdexcept_tests 0 test", NO_EXC, 0);
     679  #ifdef FE_INVALID
     680    feraiseexcept (FE_INVALID);
     681    if (EXCEPTION_TESTS (float))
     682      test_exceptions ("feholdexcept_tests FE_INVALID test",
     683  		     INVALID_EXC, 0);
     684  #endif
     685    res = feupdateenv (&saved);
     686    if (res != 0)
     687      {
     688        printf ("feupdateenv failed: %d\n", res);
     689        ++count_errors;
     690      }
     691  #if defined FE_TONEAREST && defined FE_TOWARDZERO
     692    res = fegetround ();
     693    if (res != FE_TONEAREST)
     694      {
     695        printf ("feupdateenv didn't restore rounding mode: %d\n", res);
     696        ++count_errors;
     697      }
     698  #endif
     699    if (EXCEPTION_TESTS (float))
     700      test_exceptions ("feholdexcept_tests FE_DIVBYZERO|FE_INVALID test",
     701  		     DIVBYZERO_EXC | INVALID_EXC, 0);
     702    feclearexcept (FE_ALL_EXCEPT);
     703  #ifdef FE_INVALID
     704    feraiseexcept (FE_INVALID);
     705  #endif
     706  #if defined FE_TONEAREST && defined FE_UPWARD
     707    res = fesetround (FE_UPWARD);
     708    if (res != 0 && ROUNDING_TESTS (float, FE_UPWARD))
     709      {
     710        printf ("fesetround failed: %d\n", res);
     711        ++count_errors;
     712      }
     713  #endif
     714    res = feholdexcept (&saved2);
     715    if (res != 0)
     716      {
     717        printf ("feholdexcept failed: %d\n", res);
     718        ++count_errors;
     719      }
     720  #if defined FE_TONEAREST && defined FE_UPWARD
     721    res = fesetround (FE_TONEAREST);
     722    if (res != 0)
     723      {
     724        printf ("fesetround failed: %d\n", res);
     725        ++count_errors;
     726      }
     727  #endif
     728    test_exceptions ("feholdexcept_tests 0 2nd test", NO_EXC, 0);
     729  #ifdef FE_INEXACT
     730    feraiseexcept (FE_INEXACT);
     731    if (EXCEPTION_TESTS (float))
     732      test_exceptions ("feholdexcept_tests FE_INEXACT test",
     733  		     INEXACT_EXC, 0);
     734  #endif
     735    res = feupdateenv (&saved2);
     736    if (res != 0)
     737      {
     738        printf ("feupdateenv failed: %d\n", res);
     739        ++count_errors;
     740      }
     741  #if defined FE_TONEAREST && defined FE_UPWARD
     742    res = fegetround ();
     743    if (res != FE_UPWARD && ROUNDING_TESTS (float, FE_UPWARD))
     744      {
     745        printf ("feupdateenv didn't restore rounding mode: %d\n", res);
     746        ++count_errors;
     747      }
     748    fesetround (FE_TONEAREST);
     749  #endif
     750    if (EXCEPTION_TESTS (float))
     751      test_exceptions ("feholdexcept_tests FE_INEXACT|FE_INVALID test",
     752  		     INVALID_EXC | INEXACT_EXC, 0);
     753    feclearexcept (FE_ALL_EXCEPT);
     754  }
     755  
     756  
     757  /* IEC 559 and ISO C99 define a default startup environment */
     758  static void
     759  initial_tests (void)
     760  {
     761    test_exceptions ("Initially all exceptions should be cleared",
     762                     NO_EXC, 0);
     763  #ifdef FE_TONEAREST
     764    test_rounding ("Rounding direction should be initialized to nearest",
     765                   FE_TONEAREST);
     766  #endif
     767  }
     768  
     769  int
     770  main (void)
     771  {
     772    initial_tests ();
     773    fe_tests ();
     774    feenv_tests ();
     775    feholdexcept_tests ();
     776  
     777    if (count_errors)
     778      {
     779        printf ("\n%d errors occurred.\n", count_errors);
     780        exit (1);
     781      }
     782    printf ("\n All tests passed successfully.\n");
     783    return 0;
     784  }