Back to index

glibc  2.9
test-fenv.c
Go to the documentation of this file.
00001 /* Copyright (C) 1997, 1998, 2000, 2001, 2003, 2007
00002    Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Andreas Jaeger <aj@suse.de> and
00005    Ulrich Drepper <drepper@cygnus.com>, 1997.
00006 
00007    The GNU C Library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Lesser General Public
00009    License as published by the Free Software Foundation; either
00010    version 2.1 of the License, or (at your option) any later version.
00011 
00012    The GNU C Library is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Lesser General Public License for more details.
00016 
00017    You should have received a copy of the GNU Lesser General Public
00018    License along with the GNU C Library; if not, write to the Free
00019    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00020    02111-1307 USA.  */
00021 
00022 /* Tests for ISO C99 7.6: Floating-point environment  */
00023 
00024 #ifndef _GNU_SOURCE
00025 # define _GNU_SOURCE
00026 #endif
00027 
00028 #include <complex.h>
00029 #include <math.h>
00030 #include <float.h>
00031 #include <fenv.h>
00032 
00033 #include <errno.h>
00034 #include <signal.h>
00035 #include <stdlib.h>
00036 #include <stdio.h>
00037 #include <string.h>
00038 #include <unistd.h>
00039 #include <sys/wait.h>
00040 #include <sys/resource.h>
00041 
00042 /*
00043   Since not all architectures might define all exceptions, we define
00044   a private set and map accordingly.
00045 */
00046 #define NO_EXC 0
00047 #define INEXACT_EXC 0x1
00048 #define DIVBYZERO_EXC 0x2
00049 #define UNDERFLOW_EXC 0x04
00050 #define OVERFLOW_EXC 0x08
00051 #define INVALID_EXC 0x10
00052 #define ALL_EXC \
00053         (INEXACT_EXC | DIVBYZERO_EXC | UNDERFLOW_EXC | OVERFLOW_EXC | \
00054          INVALID_EXC)
00055 
00056 static int count_errors;
00057 
00058 /* Test whether a given exception was raised.  */
00059 static void
00060 test_single_exception (short int exception,
00061                        short int exc_flag,
00062                        fexcept_t fe_flag,
00063                        const char *flag_name)
00064 {
00065   if (exception & exc_flag)
00066     {
00067       if (fetestexcept (fe_flag))
00068         printf ("  Pass: Exception \"%s\" is set\n", flag_name);
00069       else
00070         {
00071           printf ("  Fail: Exception \"%s\" is not set\n", flag_name);
00072           ++count_errors;
00073         }
00074     }
00075   else
00076     {
00077       if (fetestexcept (fe_flag))
00078         {
00079           printf ("  Fail: Exception \"%s\" is set\n", flag_name);
00080           ++count_errors;
00081         }
00082       else
00083         {
00084           printf ("  Pass: Exception \"%s\" is not set\n", flag_name);
00085         }
00086     }
00087 }
00088 
00089 static void
00090 test_exceptions (const char *test_name, short int exception,
00091                int ignore_inexact)
00092 {
00093   printf ("Test: %s\n", test_name);
00094 #ifdef FE_DIVBYZERO
00095   test_single_exception (exception, DIVBYZERO_EXC, FE_DIVBYZERO,
00096                          "DIVBYZERO");
00097 #endif
00098 #ifdef FE_INVALID
00099   test_single_exception (exception, INVALID_EXC, FE_INVALID,
00100                          "INVALID");
00101 #endif
00102 #ifdef FE_INEXACT
00103   if (!ignore_inexact)
00104     test_single_exception (exception, INEXACT_EXC, FE_INEXACT,
00105                         "INEXACT");
00106 #endif
00107 #ifdef FE_UNDERFLOW
00108   test_single_exception (exception, UNDERFLOW_EXC, FE_UNDERFLOW,
00109                          "UNDERFLOW");
00110 #endif
00111 #ifdef FE_OVERFLOW
00112   test_single_exception (exception, OVERFLOW_EXC, FE_OVERFLOW,
00113                          "OVERFLOW");
00114 #endif
00115 }
00116 
00117 static void
00118 print_rounding (int rounding)
00119 {
00120 
00121   switch (rounding)
00122     {
00123 #ifdef FE_TONEAREST
00124     case FE_TONEAREST:
00125       printf ("TONEAREST");
00126       break;
00127 #endif
00128 #ifdef FE_UPWARD
00129     case FE_UPWARD:
00130       printf ("UPWARD");
00131       break;
00132 #endif
00133 #ifdef FE_DOWNWARD
00134     case FE_DOWNWARD:
00135       printf ("DOWNWARD");
00136       break;
00137 #endif
00138 #ifdef FE_TOWARDZERO
00139     case FE_TOWARDZERO:
00140       printf ("TOWARDZERO");
00141       break;
00142 #endif
00143     }
00144   printf (".\n");
00145 }
00146 
00147 
00148 static void
00149 test_rounding (const char *test_name, int rounding_mode)
00150 {
00151   int curr_rounding = fegetround ();
00152 
00153   printf ("Test: %s\n", test_name);
00154   if (curr_rounding == rounding_mode)
00155     {
00156       printf ("  Pass: Rounding mode is ");
00157       print_rounding (curr_rounding);
00158     }
00159   else
00160     {
00161       ++count_errors;
00162       printf ("  Fail: Rounding mode is ");
00163       print_rounding (curr_rounding);
00164     }
00165 }
00166 
00167 
00168 static void
00169 set_single_exc (const char *test_name, int fe_exc, fexcept_t exception)
00170 {
00171   char str[200];
00172   /* The standard allows the inexact exception to be set together with the
00173      underflow and overflow exceptions.  So ignore the inexact flag if the
00174      others are raised.  */
00175   int ignore_inexact = (fe_exc & (UNDERFLOW_EXC | OVERFLOW_EXC)) != 0;
00176 
00177   strcpy (str, test_name);
00178   strcat (str, ": set flag, with rest not set");
00179   feclearexcept (FE_ALL_EXCEPT);
00180   feraiseexcept (exception);
00181   test_exceptions (str, fe_exc, ignore_inexact);
00182 
00183   strcpy (str, test_name);
00184   strcat (str, ": clear flag, rest also unset");
00185   feclearexcept (exception);
00186   test_exceptions (str, NO_EXC, ignore_inexact);
00187 
00188   strcpy (str, test_name);
00189   strcat (str, ": set flag, with rest set");
00190   feraiseexcept (FE_ALL_EXCEPT ^ exception);
00191   feraiseexcept (exception);
00192   test_exceptions (str, ALL_EXC, 0);
00193 
00194   strcpy (str, test_name);
00195   strcat (str, ": clear flag, leave rest set");
00196   feclearexcept (exception);
00197   test_exceptions (str, ALL_EXC ^ fe_exc, 0);
00198 }
00199 
00200 static void
00201 fe_tests (void)
00202 {
00203   /* clear all exceptions and test if all are cleared */
00204   feclearexcept (FE_ALL_EXCEPT);
00205   test_exceptions ("feclearexcept (FE_ALL_EXCEPT) clears all exceptions",
00206                    NO_EXC, 0);
00207 
00208   /* raise all exceptions and test if all are raised */
00209   feraiseexcept (FE_ALL_EXCEPT);
00210   test_exceptions ("feraiseexcept (FE_ALL_EXCEPT) raises all exceptions",
00211                    ALL_EXC, 0);
00212   feclearexcept (FE_ALL_EXCEPT);
00213 
00214 #ifdef FE_DIVBYZERO
00215   set_single_exc ("Set/Clear FE_DIVBYZERO", DIVBYZERO_EXC, FE_DIVBYZERO);
00216 #endif
00217 #ifdef FE_INVALID
00218   set_single_exc ("Set/Clear FE_INVALID", INVALID_EXC, FE_INVALID);
00219 #endif
00220 #ifdef FE_INEXACT
00221   set_single_exc ("Set/Clear FE_INEXACT", INEXACT_EXC, FE_INEXACT);
00222 #endif
00223 #ifdef FE_UNDERFLOW
00224   set_single_exc ("Set/Clear FE_UNDERFLOW", UNDERFLOW_EXC, FE_UNDERFLOW);
00225 #endif
00226 #ifdef FE_OVERFLOW
00227   set_single_exc ("Set/Clear FE_OVERFLOW", OVERFLOW_EXC, FE_OVERFLOW);
00228 #endif
00229 }
00230 
00231 /* Test that program aborts with no masked interrupts */
00232 static void
00233 feenv_nomask_test (const char *flag_name, int fe_exc)
00234 {
00235 #if defined FE_NOMASK_ENV
00236   int status;
00237   pid_t pid;
00238   fenv_t saved;
00239 
00240   fegetenv (&saved);
00241   errno = 0;
00242   fesetenv (FE_NOMASK_ENV);
00243   status = errno;
00244   fesetenv (&saved);
00245   if (status == ENOSYS)
00246     {
00247       printf ("Test: not testing FE_NOMASK_ENV, it isn't implemented.\n");
00248       return;
00249     }
00250 
00251   printf ("Test: after fesetenv (FE_NOMASK_ENV) processes will abort\n");
00252   printf ("      when feraiseexcept (%s) is called.\n", flag_name);
00253   pid = fork ();
00254   if (pid == 0)
00255     {
00256 #ifdef RLIMIT_CORE
00257       /* Try to avoid dumping core.  */
00258       struct rlimit core_limit;
00259       core_limit.rlim_cur = 0;
00260       core_limit.rlim_max = 0;
00261       setrlimit (RLIMIT_CORE, &core_limit);
00262 #endif
00263 
00264       fesetenv (FE_NOMASK_ENV);
00265       feraiseexcept (fe_exc);
00266       exit (2);
00267     }
00268   else if (pid < 0)
00269     {
00270       if (errno != ENOSYS)
00271        {
00272          printf ("  Fail: Could not fork.\n");
00273          ++count_errors;
00274        }
00275       else
00276        printf ("  `fork' not implemented, test ignored.\n");
00277     }
00278   else {
00279     if (waitpid (pid, &status, 0) != pid)
00280       {
00281        printf ("  Fail: waitpid call failed.\n");
00282        ++count_errors;
00283       }
00284     else if (WIFSIGNALED (status) && WTERMSIG (status) == SIGFPE)
00285       printf ("  Pass: Process received SIGFPE.\n");
00286     else
00287       {
00288        printf ("  Fail: Process didn't receive signal and exited with status %d.\n",
00289               status);
00290        ++count_errors;
00291       }
00292   }
00293 #endif
00294 }
00295 
00296 /* Test that program doesn't abort with default environment */
00297 static void
00298 feenv_mask_test (const char *flag_name, int fe_exc)
00299 {
00300   int status;
00301   pid_t pid;
00302 
00303   printf ("Test: after fesetenv (FE_DFL_ENV) processes will not abort\n");
00304   printf ("      when feraiseexcept (%s) is called.\n", flag_name);
00305   pid = fork ();
00306   if (pid == 0)
00307     {
00308 #ifdef RLIMIT_CORE
00309       /* Try to avoid dumping core.  */
00310       struct rlimit core_limit;
00311       core_limit.rlim_cur = 0;
00312       core_limit.rlim_max = 0;
00313       setrlimit (RLIMIT_CORE, &core_limit);
00314 #endif
00315 
00316       fesetenv (FE_DFL_ENV);
00317       feraiseexcept (fe_exc);
00318       exit (2);
00319     }
00320   else if (pid < 0)
00321     {
00322       if (errno != ENOSYS)
00323        {
00324          printf ("  Fail: Could not fork.\n");
00325          ++count_errors;
00326        }
00327       else
00328        printf ("  `fork' not implemented, test ignored.\n");
00329     }
00330   else {
00331     if (waitpid (pid, &status, 0) != pid)
00332       {
00333        printf ("  Fail: waitpid call failed.\n");
00334        ++count_errors;
00335       }
00336     else if (WIFEXITED (status) && WEXITSTATUS (status) == 2)
00337       printf ("  Pass: Process exited normally.\n");
00338     else
00339       {
00340        printf ("  Fail: Process exited abnormally with status %d.\n",
00341               status);
00342        ++count_errors;
00343       }
00344   }
00345 }
00346 
00347 /* Test that program aborts with no masked interrupts */
00348 static void
00349 feexcp_nomask_test (const char *flag_name, int fe_exc)
00350 {
00351   int status;
00352   pid_t pid;
00353 
00354   printf ("Test: after fedisableexcept (%s) processes will abort\n",
00355          flag_name);
00356   printf ("      when feraiseexcept (%s) is called.\n", flag_name);
00357   pid = fork ();
00358   if (pid == 0)
00359     {
00360 #ifdef RLIMIT_CORE
00361       /* Try to avoid dumping core.  */
00362       struct rlimit core_limit;
00363       core_limit.rlim_cur = 0;
00364       core_limit.rlim_max = 0;
00365       setrlimit (RLIMIT_CORE, &core_limit);
00366 #endif
00367 
00368       fedisableexcept (FE_ALL_EXCEPT);
00369       feenableexcept (fe_exc);
00370       feraiseexcept (fe_exc);
00371       exit (2);
00372     }
00373   else if (pid < 0)
00374     {
00375       if (errno != ENOSYS)
00376        {
00377          printf ("  Fail: Could not fork.\n");
00378          ++count_errors;
00379        }
00380       else
00381        printf ("  `fork' not implemented, test ignored.\n");
00382     }
00383   else {
00384     if (waitpid (pid, &status, 0) != pid)
00385       {
00386        printf ("  Fail: waitpid call failed.\n");
00387        ++count_errors;
00388       }
00389     else if (WIFSIGNALED (status) && WTERMSIG (status) == SIGFPE)
00390       printf ("  Pass: Process received SIGFPE.\n");
00391     else
00392       {
00393        printf ("  Fail: Process didn't receive signal and exited with status %d.\n",
00394               status);
00395        ++count_errors;
00396       }
00397   }
00398 }
00399 
00400 /* Test that program doesn't abort with exception.  */
00401 static void
00402 feexcp_mask_test (const char *flag_name, int fe_exc)
00403 {
00404   int status;
00405   int exception;
00406   pid_t pid;
00407 
00408   printf ("Test: after fedisableexcept (%s) processes will not abort\n",
00409          flag_name);
00410   printf ("      when feraiseexcept (%s) is called.\n", flag_name);
00411   pid = fork ();
00412   if (pid == 0)
00413     {
00414 #ifdef RLIMIT_CORE
00415       /* Try to avoid dumping core.  */
00416       struct rlimit core_limit;
00417       core_limit.rlim_cur = 0;
00418       core_limit.rlim_max = 0;
00419       setrlimit (RLIMIT_CORE, &core_limit);
00420 #endif
00421       feenableexcept (FE_ALL_EXCEPT);
00422       exception = fe_exc;
00423 #ifdef FE_INEXACT
00424       /* The standard allows the inexact exception to be set together with the
00425         underflow and overflow exceptions.  So add FE_INEXACT to the set of
00426         exceptions to be disabled if we will be raising underflow or
00427         overflow.  */
00428 # ifdef FE_OVERFLOW
00429       if (fe_exc & FE_OVERFLOW)
00430        exception |= FE_INEXACT;
00431 # endif
00432 # ifdef FE_UNDERFLOW
00433       if (fe_exc & FE_UNDERFLOW)
00434        exception |= FE_INEXACT;
00435 # endif
00436 #endif
00437       fedisableexcept (exception);
00438       feraiseexcept (fe_exc);
00439       exit (2);
00440     }
00441   else if (pid < 0)
00442     {
00443       if (errno != ENOSYS)
00444        {
00445          printf ("  Fail: Could not fork.\n");
00446          ++count_errors;
00447        }
00448       else
00449        printf ("  `fork' not implemented, test ignored.\n");
00450     }
00451   else {
00452     if (waitpid (pid, &status, 0) != pid)
00453       {
00454        printf ("  Fail: waitpid call failed.\n");
00455        ++count_errors;
00456       }
00457     else if (WIFEXITED (status) && WEXITSTATUS (status) == 2)
00458       printf ("  Pass: Process exited normally.\n");
00459     else
00460       {
00461        printf ("  Fail: Process exited abnormally with status %d.\n",
00462               status);
00463        ++count_errors;
00464       }
00465   }
00466 }
00467 
00468 
00469 /* Tests for feenableexcept/fedisableexcept/fegetexcept.  */
00470 static void
00471 feenable_test (const char *flag_name, int fe_exc)
00472 {
00473   int excepts;
00474 
00475 
00476   printf ("Tests for feenableexcepts etc. with flag %s\n", flag_name);
00477 
00478   /* First disable all exceptions.  */
00479   if (fedisableexcept (FE_ALL_EXCEPT) == -1)
00480     {
00481       printf ("Test: fedisableexcept (FE_ALL_EXCEPT) failed\n");
00482       ++count_errors;
00483       /* If this fails, the other tests don't make sense.  */
00484       return;
00485     }
00486   excepts = fegetexcept ();
00487   if (excepts != 0)
00488     {
00489       printf ("Test: fegetexcept (%s) failed, return should be 0, is %d\n",
00490              flag_name, excepts);
00491       ++count_errors;
00492     }
00493 
00494   excepts = feenableexcept (fe_exc);
00495   if (excepts == -1)
00496     {
00497       printf ("Test: feenableexcept (%s) failed\n", flag_name);
00498       ++count_errors;
00499       return;
00500     }
00501   if (excepts != 0)
00502     {
00503       printf ("Test: feenableexcept (%s) failed, return should be 0, is %x\n",
00504              flag_name, excepts);
00505       ++count_errors;
00506     }
00507 
00508   excepts = fegetexcept ();
00509   if (excepts != fe_exc)
00510     {
00511       printf ("Test: fegetexcept (%s) failed, return should be 0x%x, is 0x%x\n",
00512              flag_name, fe_exc, excepts);
00513       ++count_errors;
00514     }
00515 
00516   /* And now disable the exception again.  */
00517   excepts = fedisableexcept (fe_exc);
00518   if (excepts == -1)
00519     {
00520       printf ("Test: fedisableexcept (%s) failed\n", flag_name);
00521       ++count_errors;
00522       return;
00523     }
00524   if (excepts != fe_exc)
00525     {
00526       printf ("Test: fedisableexcept (%s) failed, return should be 0x%x, is 0x%x\n",
00527              flag_name, fe_exc, excepts);
00528       ++count_errors;
00529     }
00530 
00531   excepts = fegetexcept ();
00532   if (excepts != 0)
00533     {
00534       printf ("Test: fegetexcept (%s) failed, return should be 0, is 0x%x\n",
00535              flag_name, excepts);
00536       ++count_errors;
00537     }
00538 
00539   /* Now the other way round: Enable all exceptions and disable just this one.  */
00540   if (feenableexcept (FE_ALL_EXCEPT) == -1)
00541     {
00542       printf ("Test: feenableexcept (FE_ALL_EXCEPT) failed\n");
00543       ++count_errors;
00544       /* If this fails, the other tests don't make sense.  */
00545       return;
00546     }
00547 
00548   excepts = fegetexcept ();
00549   if (excepts != FE_ALL_EXCEPT)
00550     {
00551       printf ("Test: fegetexcept (%s) failed, return should be 0x%x, is 0x%x\n",
00552              flag_name, FE_ALL_EXCEPT, excepts);
00553       ++count_errors;
00554     }
00555 
00556   excepts = fedisableexcept (fe_exc);
00557   if (excepts == -1)
00558     {
00559       printf ("Test: fedisableexcept (%s) failed\n", flag_name);
00560       ++count_errors;
00561       return;
00562     }
00563   if (excepts != FE_ALL_EXCEPT)
00564     {
00565       printf ("Test: fedisableexcept (%s) failed, return should be 0, is 0x%x\n",
00566              flag_name, excepts);
00567       ++count_errors;
00568     }
00569 
00570   excepts = fegetexcept ();
00571   if (excepts != (FE_ALL_EXCEPT & ~fe_exc))
00572     {
00573       printf ("Test: fegetexcept (%s) failed, return should be 0x%x, is 0x%x\n",
00574              flag_name, (FE_ALL_EXCEPT & ~fe_exc), excepts);
00575       ++count_errors;
00576     }
00577 
00578   /* And now enable the exception again.  */
00579   excepts = feenableexcept (fe_exc);
00580   if (excepts == -1)
00581     {
00582       printf ("Test: feenableexcept (%s) failed\n", flag_name);
00583       ++count_errors;
00584       return;
00585     }
00586   if (excepts != (FE_ALL_EXCEPT & ~fe_exc))
00587     {
00588       printf ("Test: feenableexcept (%s) failed, return should be 0, is 0x%x\n",
00589              flag_name, excepts);
00590       ++count_errors;
00591     }
00592 
00593   excepts = fegetexcept ();
00594   if (excepts != FE_ALL_EXCEPT)
00595     {
00596       printf ("Test: fegetexcept (%s) failed, return should be 0x%x, is 0x%x\n",
00597              flag_name, FE_ALL_EXCEPT, excepts);
00598       ++count_errors;
00599     }
00600   feexcp_nomask_test (flag_name, fe_exc);
00601   feexcp_mask_test (flag_name, fe_exc);
00602 
00603 }
00604 
00605 
00606 static void
00607 fe_single_test (const char *flag_name, int fe_exc)
00608 {
00609   feenv_nomask_test (flag_name, fe_exc);
00610   feenv_mask_test (flag_name, fe_exc);
00611   feenable_test (flag_name, fe_exc);
00612 }
00613 
00614 
00615 static void
00616 feenv_tests (void)
00617 {
00618   /* We might have some exceptions still set.  */
00619   feclearexcept (FE_ALL_EXCEPT);
00620 
00621 #ifdef FE_DIVBYZERO
00622   fe_single_test ("FE_DIVBYZERO", FE_DIVBYZERO);
00623 #endif
00624 #ifdef FE_INVALID
00625   fe_single_test ("FE_INVALID", FE_INVALID);
00626 #endif
00627 #ifdef FE_INEXACT
00628   fe_single_test ("FE_INEXACT", FE_INEXACT);
00629 #endif
00630 #ifdef FE_UNDERFLOW
00631   fe_single_test ("FE_UNDERFLOW", FE_UNDERFLOW);
00632 #endif
00633 #ifdef FE_OVERFLOW
00634   fe_single_test ("FE_OVERFLOW", FE_OVERFLOW);
00635 #endif
00636   fesetenv (FE_DFL_ENV);
00637 }
00638 
00639 
00640 static void
00641 feholdexcept_tests (void)
00642 {
00643   fenv_t saved, saved2;
00644   int res;
00645 
00646   feclearexcept (FE_ALL_EXCEPT);
00647   fedisableexcept (FE_ALL_EXCEPT);
00648 #ifdef FE_DIVBYZERO
00649   feraiseexcept (FE_DIVBYZERO);
00650 #endif
00651   test_exceptions ("feholdexcept_tests FE_DIVBYZERO test",
00652                  DIVBYZERO_EXC, 0);
00653   res = feholdexcept (&saved);
00654   if (res != 0)
00655     {
00656       printf ("feholdexcept failed: %d\n", res);
00657       ++count_errors;
00658     }
00659 #if defined FE_TONEAREST && defined FE_TOWARDZERO
00660   res = fesetround (FE_TOWARDZERO);
00661   if (res != 0)
00662     {
00663       printf ("fesetround failed: %d\n", res);
00664       ++count_errors;
00665     }
00666 #endif
00667   test_exceptions ("feholdexcept_tests 0 test", NO_EXC, 0);
00668   feraiseexcept (FE_INVALID);
00669   test_exceptions ("feholdexcept_tests FE_INVALID test",
00670                  INVALID_EXC, 0);
00671   res = feupdateenv (&saved);
00672   if (res != 0)
00673     {
00674       printf ("feupdateenv failed: %d\n", res);
00675       ++count_errors;
00676     }
00677 #if defined FE_TONEAREST && defined FE_TOWARDZERO
00678   res = fegetround ();
00679   if (res != FE_TONEAREST)
00680     {
00681       printf ("feupdateenv didn't restore rounding mode: %d\n", res);
00682       ++count_errors;
00683     }
00684 #endif
00685   test_exceptions ("feholdexcept_tests FE_DIVBYZERO|FE_INVALID test",
00686                  DIVBYZERO_EXC | INVALID_EXC, 0);
00687   feclearexcept (FE_ALL_EXCEPT);
00688   feraiseexcept (FE_INVALID);
00689 #if defined FE_TONEAREST && defined FE_UPWARD
00690   res = fesetround (FE_UPWARD);
00691   if (res != 0)
00692     {
00693       printf ("fesetround failed: %d\n", res);
00694       ++count_errors;
00695     }
00696 #endif
00697   res = feholdexcept (&saved2);
00698   if (res != 0)
00699     {
00700       printf ("feholdexcept failed: %d\n", res);
00701       ++count_errors;
00702     }
00703 #if defined FE_TONEAREST && defined FE_UPWARD
00704   res = fesetround (FE_TONEAREST);
00705   if (res != 0)
00706     {
00707       printf ("fesetround failed: %d\n", res);
00708       ++count_errors;
00709     }
00710 #endif
00711   test_exceptions ("feholdexcept_tests 0 2nd test", NO_EXC, 0);
00712   feraiseexcept (FE_INEXACT);
00713   test_exceptions ("feholdexcept_tests FE_INEXACT test",
00714                  INEXACT_EXC, 0);
00715   res = feupdateenv (&saved2);
00716   if (res != 0)
00717     {
00718       printf ("feupdateenv failed: %d\n", res);
00719       ++count_errors;
00720     }
00721 #if defined FE_TONEAREST && defined FE_UPWARD
00722   res = fegetround ();
00723   if (res != FE_UPWARD)
00724     {
00725       printf ("feupdateenv didn't restore rounding mode: %d\n", res);
00726       ++count_errors;
00727     }
00728   fesetround (FE_TONEAREST);
00729 #endif
00730   test_exceptions ("feholdexcept_tests FE_INEXACT|FE_INVALID test",
00731                  INVALID_EXC | INEXACT_EXC, 0);
00732   feclearexcept (FE_ALL_EXCEPT);
00733 }
00734 
00735 
00736 /* IEC 559 and ISO C99 define a default startup environment */
00737 static void
00738 initial_tests (void)
00739 {
00740   test_exceptions ("Initially all exceptions should be cleared",
00741                    NO_EXC, 0);
00742 #ifdef FE_TONEAREST
00743   test_rounding ("Rounding direction should be initalized to nearest",
00744                  FE_TONEAREST);
00745 #endif
00746 }
00747 
00748 int
00749 main (void)
00750 {
00751   initial_tests ();
00752   fe_tests ();
00753   feenv_tests ();
00754   feholdexcept_tests ();
00755 
00756   if (count_errors)
00757     {
00758       printf ("\n%d errors occurred.\n", count_errors);
00759       exit (1);
00760     }
00761   printf ("\n All tests passed successfully.\n");
00762   return 0;
00763 }