kernel: print spurious interrupt message with increasing interval.
[minix.git] / test / test47.c
blobf75a04df0edd6fea8ea5db0c484966faebce3ee2
1 #include <assert.h>
2 #include <fenv.h>
3 #include <math.h>
4 #include <signal.h>
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <sys/sigcontext.h>
10 #define MAX_ERROR 4
11 static int errct;
13 /* maximum allowed FP difference for our tests */
14 #define EPSILON 0.00000000023283064365386962890625 /* 2^(-32) */
16 static void quit(void)
18 if (errct == 0)
20 printf("ok\n");
21 exit(0);
23 else
25 printf("%d errors\n", errct);
26 exit(1);
30 #define ERR(x, y) e(__LINE__, (x), (y))
32 static void e(int n, double x, double y)
34 printf("Line %d, x=%.20g, y=%.20g\n", n, x, y);
35 if (errct++ > MAX_ERROR)
37 printf("Too many errors; test aborted\n");
38 exit(1);
42 static void signal_handler(int signum)
44 struct sigframe *sigframe;
46 /* report signal */
47 sigframe = (struct sigframe *) ((char *) &signum -
48 (char *) &((struct sigframe *) NULL)->sf_signo);
49 printf("Signal %d at 0x%x\n", signum, sigframe->sf_scp->sc_regs.pc);
51 /* count as error */
52 ERR(0, 0);
53 fflush(stdout);
55 /* handle signa again next time */
56 signal(signum, signal_handler);
59 static void test_fpclassify(double value, int class, int test_sign)
61 /* test fpclassify */
62 if (fpclassify(value) != class) ERR(value, 0);
63 if (test_sign)
65 if (fpclassify(-value) != class) ERR(-value, 0);
67 /* test signbit */
68 if (signbit(value)) ERR(value, 0);
69 if (!signbit(-value)) ERR(-value, 0);
73 /* Maximum normal double: (2 - 2^(-53)) * 2^1023 */
74 #define NORMAL_DOUBLE_MAX 1.797693134862315708145274237317e+308
76 /* Minimum normal double: 2^(-1022) */
77 #define NORMAL_DOUBLE_MIN 2.2250738585072013830902327173324e-308
79 /* Maximum subnormal double: (1 - 2^(-53)) * 2^(-1022) */
80 #define SUBNORMAL_DOUBLE_MAX 2.2250738585072008890245868760859e-308
82 /* Minimum subnormal double: 2^(-52) * 2^(-1023) */
83 #define SUBNORMAL_DOUBLE_MIN 4.9406564584124654417656879286822e-324
85 static void test_fpclassify_values(void)
87 double d;
88 char negzero[] = { 0, 0, 0, 0, 0, 0, 0, 0x80 };
90 /* test some corner cases for fpclassify and signbit */
91 test_fpclassify(INFINITY, FP_INFINITE, 1);
92 test_fpclassify(NAN, FP_NAN, 0);
93 test_fpclassify(0, FP_ZERO, 0);
94 test_fpclassify(1, FP_NORMAL, 1);
95 test_fpclassify(NORMAL_DOUBLE_MAX, FP_NORMAL, 1);
96 test_fpclassify(NORMAL_DOUBLE_MIN, FP_NORMAL, 1);
97 test_fpclassify(SUBNORMAL_DOUBLE_MAX, FP_SUBNORMAL, 1);
98 test_fpclassify(SUBNORMAL_DOUBLE_MIN, FP_SUBNORMAL, 1);
101 * unfortunately the minus operator does not change the sign of zero,
102 * so a special case is needed to test it
104 assert(sizeof(negzero) == sizeof(double));
105 test_fpclassify(*(double *) negzero, FP_ZERO, 0);
106 if (!signbit(*(double *) negzero)) ERR(0, 0);
108 /* test other small numbers for fpclassify and signbit */
109 d = 1;
110 while (d >= NORMAL_DOUBLE_MIN)
112 test_fpclassify(d, FP_NORMAL, 1);
113 d /= 10;
115 while (d >= SUBNORMAL_DOUBLE_MIN)
117 test_fpclassify(d, FP_SUBNORMAL, 1);
118 d /= 10;
120 test_fpclassify(d, FP_ZERO, 0);
122 /* test other large numbers for fpclassify and signbit */
123 d = 1;
124 while (d <= NORMAL_DOUBLE_MAX / 10)
126 test_fpclassify(d, FP_NORMAL, 1);
127 d *= 10;
131 /* expected rounding: up, down or identical */
132 #define ROUND_EQ 1
133 #define ROUND_DN 2
134 #define ROUND_UP 3
136 static void test_round_value_mode_func(double value, int mode, double (*func)(double), int exp)
138 int mode_old;
139 double rounded;
141 /* update and check rounding mode */
142 mode_old = fegetround();
143 fesetround(mode);
144 if (fegetround() != mode) ERR(0, 0);
146 /* perform rounding */
147 rounded = func(value);
149 /* check direction of rounding */
150 switch (exp)
152 case ROUND_EQ: if (rounded != value) ERR(value, rounded); break;
153 case ROUND_DN: if (rounded >= value) ERR(value, rounded); break;
154 case ROUND_UP: if (rounded <= value) ERR(value, rounded); break;
155 default: assert(0);
158 /* check whether the number is sufficiently close */
159 if (fabs(value - rounded) >= 1) ERR(value, rounded);
161 /* check whether the number is integer */
162 if (remainder(rounded, 1)) ERR(value, rounded);
164 /* re-check and restore rounding mode */
165 if (fegetround() != mode) ERR(0, 0);
166 fesetround(mode_old);
169 static void test_round_value_mode(double value, int mode, int exp_nearbyint,
170 int exp_ceil, int exp_floor, int exp_trunc)
172 /* test both nearbyint and trunc */
173 test_round_value_mode_func(value, mode, nearbyint, exp_nearbyint);
174 test_round_value_mode_func(value, mode, ceil, exp_ceil);
175 test_round_value_mode_func(value, mode, floor, exp_floor);
176 test_round_value_mode_func(value, mode, trunc, exp_trunc);
179 static void test_round_value(double value, int exp_down, int exp_near, int exp_up, int exp_trunc)
181 /* test each rounding mode */
182 test_round_value_mode(value, FE_DOWNWARD, exp_down, exp_up, exp_down, exp_trunc);
183 test_round_value_mode(value, FE_TONEAREST, exp_near, exp_up, exp_down, exp_trunc);
184 test_round_value_mode(value, FE_UPWARD, exp_up, exp_up, exp_down, exp_trunc);
185 test_round_value_mode(value, FE_TOWARDZERO, exp_trunc, exp_up, exp_down, exp_trunc);
188 static void test_round_values(void)
190 int i;
192 /* test various values */
193 for (i = -100000; i < 100000; i++)
195 test_round_value(i + 0.00, ROUND_EQ, ROUND_EQ, ROUND_EQ, ROUND_EQ);
196 test_round_value(i + 0.25, ROUND_DN, ROUND_DN, ROUND_UP, (i >= 0) ? ROUND_DN : ROUND_UP);
197 test_round_value(i + 0.50, ROUND_DN, (i % 2) ? ROUND_UP : ROUND_DN, ROUND_UP, (i >= 0) ? ROUND_DN : ROUND_UP);
198 test_round_value(i + 0.75, ROUND_DN, ROUND_UP, ROUND_UP, (i >= 0) ? ROUND_DN : ROUND_UP);
202 static void test_remainder_value(double x, double y)
204 int mode_old;
205 double r1, r2, z;
207 assert(y != 0);
209 /* compute remainder using the function */
210 r1 = remainder(x, y);
212 /* compute remainder using alternative approach */
213 mode_old = fegetround();
214 fesetround(FE_TONEAREST);
215 r2 = x - nearbyint(x / y) * y;
216 fesetround(mode_old);
218 /* Compare results */
219 if (fabs(r1 - r2) > EPSILON && fabs(r1 + r2) > EPSILON)
221 printf("%.20g != %.20g\n", r1, r2);
222 ERR(x, y);
226 static void test_remainder_values_y(double x)
228 int i, j;
230 /* try various rational and transcendental values for y (except zero) */
231 for (i = -50; i <= 50; i++)
232 if (i != 0)
233 for (j = 1; j < 10; j++)
235 test_remainder_value(x, (double) i / (double) j);
236 test_remainder_value(x, i * M_E + j * M_PI);
240 static void test_remainder_values_xy(void)
242 int i, j;
244 /* try various rational and transcendental values for x */
245 for (i = -50; i <= 50; i++)
246 for (j = 1; j < 10; j++)
248 test_remainder_values_y((double) i / (double) j);
249 test_remainder_values_y(i * M_E + j * M_PI);
253 int main(int argc, char **argv)
255 fenv_t fenv;
256 int i;
258 printf("Test 47 ");
259 fflush(stdout);
261 /* no FPU errors, please */
262 if (feholdexcept(&fenv) < 0) ERR(0, 0);
264 /* some signals count as errors */
265 for (i = 0; i < _NSIG; i++)
266 if (i != SIGINT && i != SIGTERM && i != SIGKILL)
267 signal(i, signal_handler);
269 /* test various floating point support functions */
270 test_fpclassify_values();
271 test_remainder_values_xy();
272 test_round_values();
273 quit();
274 return -1;