(test_exceptions): Add IGNORE_INEXACT argument,
[kopensolaris-gnu/glibc.git] / math / test-fenv.c
1 /* Copyright (C) 1997 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Andreas Jaeger <aj@arthur.rhein-neckar.de> and
4    Ulrich Drepper <drepper@cygnus.com>, 1997.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Library General Public License as
8    published by the Free Software Foundation; either version 2 of the
9    License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Library General Public License for more details.
15
16    You should have received a copy of the GNU Library General Public
17    License along with the GNU C Library; see the file COPYING.LIB.  If not,
18    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.  */
20
21 /* Tests for ISO C 9X 7.6: Floating-point environment  */
22
23 #ifndef _GNU_SOURCE
24 # define _GNU_SOURCE
25 #endif
26
27 #include <complex.h>
28 #include <math.h>
29 #include <float.h>
30 #include <fenv.h>
31
32 #include <errno.h>
33 #include <signal.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <sys/wait.h>
39
40 /*
41   Since not all architectures might define all exceptions, we define
42   a private set and map accordingly.
43 */
44 #define NO_EXC 0
45 #define INEXACT_EXC 0x1
46 #define DIVBYZERO_EXC 0x2
47 #define UNDERFLOW_EXC 0x04
48 #define OVERFLOW_EXC 0x08
49 #define INVALID_EXC 0x10
50 #define ALL_EXC \
51         (INEXACT_EXC | DIVBYZERO_EXC | UNDERFLOW_EXC | OVERFLOW_EXC | \
52          INVALID_EXC)
53
54 static int count_errors;
55
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
87 static void
88 test_exceptions (const char *test_name, short int exception,
89                  int ignore_inexact)
90 {
91   printf ("Test: %s\n", test_name);
92 #ifdef FE_DIVBYZERO
93   test_single_exception (exception, DIVBYZERO_EXC, FE_DIVBYZERO,
94                          "DIVBYZERO");
95 #endif
96 #ifdef FE_INVALID
97   test_single_exception (exception, INVALID_EXC, FE_INVALID,
98                          "INVALID");
99 #endif
100 #ifdef FE_INEXACT
101   if (!ignore_inexact)
102     test_single_exception (exception, INEXACT_EXC, FE_INEXACT,
103                            "INEXACT");
104 #endif
105 #ifdef FE_UNDERFLOW
106   test_single_exception (exception, UNDERFLOW_EXC, FE_UNDERFLOW,
107                          "UNDERFLOW");
108 #endif
109 #ifdef FE_OVERFLOW
110   test_single_exception (exception, OVERFLOW_EXC, FE_OVERFLOW,
111                          "OVERFLOW");
112 #endif
113 }
114
115 static void
116 print_rounding (int rounding)
117 {
118
119   switch (rounding) {
120 #ifdef FE_TONEAREST
121   case FE_TONEAREST:
122     printf ("TONEAREST");
123     break;
124 #endif
125 #ifdef FE_UPWARD
126   case FE_UPWARD:
127     printf ("UPWARD");
128     break;
129 #endif
130 #ifdef FE_DOWNWARD
131   case FE_DOWNWARD:
132     printf ("DOWNWARD");
133     break;
134 #endif
135 #ifdef FE_TOWARDZERO
136   case FE_TOWARDZERO:
137     printf ("TOWARDZERO");
138     break;
139 #endif
140   }
141   printf (".\n");
142 }
143
144
145 static void
146 test_rounding (const char *test_name, int rounding_mode)
147 {
148   int curr_rounding = fegetround ();
149
150   printf ("Test: %s\n", test_name);
151   if (curr_rounding == rounding_mode)
152     {
153       printf ("  Pass: Rounding mode is ");
154       print_rounding (curr_rounding);
155     }
156   else {
157     ++count_errors;
158     printf ("  Fail: Rounding mode is ");
159     print_rounding (curr_rounding);
160   }
161 }
162
163
164 static void
165 set_single_exc (const char *test_name, int fe_exc, fexcept_t exception)
166 {
167   char str[200];
168   /* The standard allows the inexact exception to be set together with the
169      underflow and overflow exceptions.  So ignore the inexact flag if the
170      others are raised.  */
171   int ignore_inexact = (fe_exc & (UNDERFLOW_EXC | OVERFLOW_EXC)) != 0;
172
173   strcpy (str, test_name);
174   strcat (str, ": set flag, with rest not set");
175   feclearexcept (FE_ALL_EXCEPT);
176   feraiseexcept (exception);
177   test_exceptions (str, fe_exc, ignore_inexact);
178
179   strcpy (str, test_name);
180   strcat (str, ": clear flag, rest also unset");
181   feclearexcept (exception);
182   test_exceptions (str, NO_EXC, ignore_inexact);
183
184   strcpy (str, test_name);
185   strcat (str, ": set flag, with rest set");
186   feraiseexcept (FE_ALL_EXCEPT ^ exception);
187   feraiseexcept (exception);
188   test_exceptions (str, ALL_EXC, 0);
189
190   strcpy (str, test_name);
191   strcat (str, ": clear flag, leave rest set");
192   feclearexcept (exception);
193   test_exceptions (str, ALL_EXC ^ fe_exc, 0);
194 }
195
196 static void
197 fe_tests (void)
198 {
199   /* clear all exceptions and test if all are cleared */
200   feclearexcept (FE_ALL_EXCEPT);
201   test_exceptions ("feclearexcept (FE_ALL_EXCEPT) clears all exceptions",
202                    NO_EXC, 0);
203
204   /* raise all exceptions and test if all are raised */
205   feraiseexcept (FE_ALL_EXCEPT);
206   test_exceptions ("feraiseexcept (FE_ALL_EXCEPT) raises all exceptions",
207                    ALL_EXC, 0);
208   feclearexcept (FE_ALL_EXCEPT);
209
210 #ifdef FE_DIVBYZERO
211   set_single_exc ("Set/Clear FE_DIVBYZERO", DIVBYZERO_EXC, FE_DIVBYZERO);
212 #endif
213 #ifdef FE_INVALID
214   set_single_exc ("Set/Clear FE_INVALID", INVALID_EXC, FE_INVALID);
215 #endif
216 #ifdef FE_INEXACT
217   set_single_exc ("Set/Clear FE_INEXACT", INEXACT_EXC, FE_INEXACT);
218 #endif
219 #ifdef FE_UNDERFLOW
220   set_single_exc ("Set/Clear FE_UNDERFLOW", UNDERFLOW_EXC, FE_UNDERFLOW);
221 #endif
222 #ifdef FE_OVERFLOW
223   set_single_exc ("Set/Clear FE_OVERFLOW", OVERFLOW_EXC, FE_OVERFLOW);
224 #endif
225 }
226
227 /* Test that program aborts with no masked interrupts */
228 static void
229 feenv_nomask_test (const char *flag_name, int fe_exc)
230 {
231   int status;
232   pid_t pid;
233
234   printf ("Test: after fesetenv (FE_NOMASK_ENV) processes will abort\n");
235   printf ("      when feraiseexcept (%s) is called.\n", flag_name);
236   pid = fork  ();
237   if (pid == 0)
238     {
239       fesetenv (FE_NOMASK_ENV);
240       feraiseexcept (fe_exc);
241       exit (2);
242     }
243   else if (pid < 0)
244     {
245       if (errno != ENOSYS)
246         {
247           printf ("  Fail: Could not fork.\n");
248           ++count_errors;
249         }
250       else
251         printf ("  `fork' not implemented, test ignored.\n");
252     }
253   else {
254     if (waitpid (pid, &status, 0) != pid)
255       {
256         printf ("  Fail: waitpid call failed.\n");
257         ++count_errors;
258       }
259     else if (WIFSIGNALED (status) && WTERMSIG (status) == SIGFPE)
260       printf ("  Pass: Process received SIGFPE.\n");
261     else
262       {
263         printf ("  Fail: Process didn't receive signal and exited with status %d.\n",
264                 status);
265         ++count_errors;
266       }
267   }
268 }
269
270 /* Test that program doesn't abort with default environment */
271 static void
272 feenv_mask_test (const char *flag_name, int fe_exc)
273 {
274   int status;
275   pid_t pid;
276
277   printf ("Test: after fesetenv (FE_DFL_ENV) processes will not abort\n");
278   printf ("      when feraiseexcept (%s) is called.\n", flag_name);
279   pid = fork ();
280   if (pid == 0)
281     {
282       fesetenv (FE_DFL_ENV);
283       feraiseexcept (fe_exc);
284       exit (2);
285     }
286   else if (pid < 0)
287     {
288       if (errno != ENOSYS)
289         {
290           printf ("  Fail: Could not fork.\n");
291           ++count_errors;
292         }
293       else
294         printf ("  `fork' not implemented, test ignored.\n");
295     }
296   else {
297     if (waitpid (pid, &status, 0) != pid)
298       {
299         printf ("  Fail: waitpid call failed.\n");
300         ++count_errors;
301       }
302     else if (WIFEXITED (status) && WEXITSTATUS (status) == 2)
303       printf ("  Pass: Process exited normally.\n");
304     else
305       {
306         printf ("  Fail: Process exited abnormally with status %d.\n",
307                 status);
308         ++count_errors;
309       }
310   }
311 }
312
313
314
315 static void
316 feenv_tests (void)
317 {
318
319 #ifdef FE_DIVBYZERO
320   feenv_nomask_test ("FE_DIVBYZERO", FE_DIVBYZERO);
321   feenv_mask_test ("FE_DIVBYZERO", FE_DIVBYZERO);
322 #endif
323 #ifdef FE_INVALID
324   feenv_nomask_test ("FE_INVALID", FE_INVALID);
325   feenv_mask_test ("FE_INVALID", FE_INVALID);
326 #endif
327 #ifdef FE_INEXACT
328   feenv_nomask_test ("FE_INEXACT", FE_INEXACT);
329   feenv_mask_test ("FE_INEXACT", FE_INEXACT);
330 #endif
331 #ifdef FE_UNDERFLOW
332   feenv_nomask_test ("FE_UNDERFLOW", FE_UNDERFLOW);
333   feenv_mask_test ("FE_UNDERFLOW", FE_UNDERFLOW);
334 #endif
335 #ifdef FE_OVERFLOW
336   feenv_nomask_test ("FE_OVERFLOW", FE_OVERFLOW);
337   feenv_mask_test ("FE_OVERFLOW", FE_OVERFLOW);
338 #endif
339   fesetenv (FE_DFL_ENV);
340 }
341
342
343 /* IEC 559 and ISO C 9X define a default startup environment */
344 static void
345 initial_tests (void)
346 {
347   test_exceptions ("Initially all exceptions should be cleared",
348                    NO_EXC, 0);
349   test_rounding ("Rounding direction should be initalized to nearest",
350                  FE_TONEAREST);
351 }
352
353 int
354 main (void)
355 {
356   initial_tests ();
357   fe_tests ();
358   feenv_tests ();
359
360   if (count_errors)
361     {
362       printf ("\n%d errors occured.\n", count_errors);
363       exit (1);
364     }
365   printf ("\n All tests passed successfully.\n");
366   exit (0);
367 }