aboutsummaryrefslogtreecommitdiff
path: root/math/test-fenv.c
blob: 55114cc13b65dc5e61d4b8fa92c769068629dad2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/* Test for exception handling functions of libm */

#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif

#include <complex.h>
#include <math.h>
#include <float.h>
#include <fenv.h>

#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/*
  Since not all architectures might define all exceptions, we define
  a private set and map accordingly.
*/
#define NO_EXC 0
#define INEXACT_EXC 0x1
#define DIVBYZERO_EXC 0x2
#define UNDERFLOW_EXC 0x04
#define OVERFLOW_EXC 0x08
#define INVALID_EXC 0x10
#define ALL_EXC \
        (INEXACT_EXC | DIVBYZERO_EXC | UNDERFLOW_EXC | OVERFLOW_EXC | \
         INVALID_EXC)

static int count_errors;

/* Test whether a given exception was raised.  */
static void
test_single_exception (short int exception,
                       short int exc_flag,
                       fexcept_t fe_flag,
                       const char *flag_name)
{
  if (exception & exc_flag)
    {
      if (fetestexcept (fe_flag))
        printf ("  Pass: Exception \"%s\" is set\n", flag_name);
      else
        {
          printf ("  Fail: Exception \"%s\" is not set\n", flag_name);
          ++count_errors;
        }
    }
  else
    {
      if (fetestexcept (fe_flag))
        {
          printf ("  Fail: Exception \"%s\" is set\n", flag_name);
          ++count_errors;
        }
      else
        {
          printf ("  Pass: Exception \"%s\" is not set\n", flag_name);
        }
    }
}

static void
test_exceptions (const char *test_name, short int exception)
{
  printf ("Test: %s\n", test_name);
#ifdef FE_DIVBYZERO
  test_single_exception (exception, DIVBYZERO_EXC, FE_DIVBYZERO,
                         "DIVBYZERO");
#endif
#ifdef FE_INVALID
  test_single_exception (exception, INVALID_EXC, FE_INVALID,
                         "INVALID");
#endif
#ifdef FE_INEXACT
  test_single_exception (exception, INEXACT_EXC, FE_INEXACT,
                         "INEXACT");
#endif
#ifdef FE_UNDERFLOW
  test_single_exception (exception, UNDERFLOW_EXC, FE_UNDERFLOW,
                         "UNDERFLOW");
#endif
#ifdef FE_OVERFLOW
  test_single_exception (exception, OVERFLOW_EXC, FE_OVERFLOW,
                         "OVERFLOW");
#endif
}


static void
set_single_exc (const char *test_name, int fe_exc, fexcept_t exception)
{
  char str[200];

  strcpy (str, test_name);
  strcat (str, ": set flag, with rest not set");
  feclearexcept (FE_ALL_EXCEPT);
  feraiseexcept (exception);
  test_exceptions (str, fe_exc);

  strcpy (str, test_name);
  strcat (str, ": clear flag, rest also unset");
  feclearexcept (exception);
  test_exceptions (str, NO_EXC);

  strcpy (str, test_name);
  strcat (str, ": set flag, with rest set");
  feraiseexcept (FE_ALL_EXCEPT ^ exception);
  feraiseexcept (exception);
  test_exceptions (str, ALL_EXC);

  strcpy (str, test_name);
  strcat (str, ": clear flag, leave rest set");
  feclearexcept (exception);
  test_exceptions (str, ALL_EXC ^ fe_exc);
}

static void
fe_tests (void)
{
  /* clear all exceptions and test if all are cleared */
  feclearexcept (FE_ALL_EXCEPT);
  test_exceptions ("feclearexcept (FE_ALL_EXCEPT) clears all exceptions",
                   NO_EXC);

  /* raise all exceptions and test if all are raised */
  feraiseexcept (FE_ALL_EXCEPT);
  test_exceptions ("feraiseexcept (FE_ALL_EXCEPT) raises all exceptions",
                   ALL_EXC);
  feclearexcept (FE_ALL_EXCEPT);


#ifdef FE_DIVBYZERO
  set_single_exc ("Set/Clear FE_DIVBYZERO", DIVBYZERO_EXC, FE_DIVBYZERO);
#endif
#ifdef FE_INVALID
  set_single_exc ("Set/Clear FE_INVALID", INVALID_EXC, FE_INVALID);
#endif
#ifdef FE_INEXACT
  set_single_exc ("Set/Clear FE_INEXACT", INEXACT_EXC, FE_INEXACT);
#endif
#ifdef FE_UNDERFLOW
  set_single_exc ("Set/Clear FE_UNDERFLOW", UNDERFLOW_EXC, FE_UNDERFLOW);
#endif
#ifdef FE_OVERFLOW
  set_single_exc ("Set/Clear FE_OVERFLOW", OVERFLOW_EXC, FE_OVERFLOW);
#endif
}

int
main (void)
{
  fe_tests ();
  /* _LIB_VERSION = _SVID;*/

  if (count_errors)
    {
      printf ("\n%d errors occured.\n", count_errors);
      exit (1);
    }
  printf ("\n All tests passed successfully.\n");
  exit (0);
}