xref: /minix3/minix/tests/test47.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc #include <assert.h>
2*433d6423SLionel Sambuc #include <fenv.h>
3*433d6423SLionel Sambuc #include <math.h>
4*433d6423SLionel Sambuc #include <signal.h>
5*433d6423SLionel Sambuc #include <stdlib.h>
6*433d6423SLionel Sambuc #include <stdio.h>
7*433d6423SLionel Sambuc #include <string.h>
8*433d6423SLionel Sambuc #include <machine/frame.h>
9*433d6423SLionel Sambuc 
10*433d6423SLionel Sambuc int max_error = 4;
11*433d6423SLionel Sambuc #include "common.h"
12*433d6423SLionel Sambuc 
13*433d6423SLionel Sambuc 
14*433d6423SLionel Sambuc /* maximum allowed FP difference for our tests */
15*433d6423SLionel Sambuc #define EPSILON 0.00000000023283064365386962890625 /* 2^(-32) */
16*433d6423SLionel Sambuc 
17*433d6423SLionel Sambuc #define ERR(x, y) e(__LINE__, (x), (y))
18*433d6423SLionel Sambuc 
signal_handler(int signum)19*433d6423SLionel Sambuc static void signal_handler(int signum)
20*433d6423SLionel Sambuc {
21*433d6423SLionel Sambuc 	struct sigframe_sigcontext *sigframe;
22*433d6423SLionel Sambuc 
23*433d6423SLionel Sambuc 	/* report signal */
24*433d6423SLionel Sambuc 	sigframe = (struct sigframe_sigcontext *) ((char *) &signum -
25*433d6423SLionel Sambuc 		(char *) &((struct sigframe_sigcontext *) NULL)->sf_signum);
26*433d6423SLionel Sambuc 	printf("Signal %d at 0x%x\n", signum, sigframe->sf_scp->sc_eip);
27*433d6423SLionel Sambuc 
28*433d6423SLionel Sambuc 	/* count as error */
29*433d6423SLionel Sambuc 	e(0);
30*433d6423SLionel Sambuc 	fflush(stdout);
31*433d6423SLionel Sambuc 
32*433d6423SLionel Sambuc 	/* handle signa again next time */
33*433d6423SLionel Sambuc 	signal(signum, signal_handler);
34*433d6423SLionel Sambuc }
35*433d6423SLionel Sambuc 
test_fpclassify(double value,int class,int test_sign)36*433d6423SLionel Sambuc static void test_fpclassify(double value, int class, int test_sign)
37*433d6423SLionel Sambuc {
38*433d6423SLionel Sambuc 	/* test fpclassify */
39*433d6423SLionel Sambuc 	if (fpclassify(value) != class) e(101);
40*433d6423SLionel Sambuc 	if (test_sign)
41*433d6423SLionel Sambuc 	{
42*433d6423SLionel Sambuc 		if (fpclassify(-value) != class) e(102);
43*433d6423SLionel Sambuc 
44*433d6423SLionel Sambuc 		/* test signbit */
45*433d6423SLionel Sambuc 		if (signbit(value))   e(103);
46*433d6423SLionel Sambuc 		if (!signbit(-value)) e(104);
47*433d6423SLionel Sambuc 	}
48*433d6423SLionel Sambuc }
49*433d6423SLionel Sambuc 
50*433d6423SLionel Sambuc /* Maximum normal double: (2 - 2^(-53)) * 2^1023 */
51*433d6423SLionel Sambuc #define NORMAL_DOUBLE_MAX 1.797693134862315708145274237317e+308
52*433d6423SLionel Sambuc 
53*433d6423SLionel Sambuc /* Minimum normal double: 2^(-1022) */
54*433d6423SLionel Sambuc #define NORMAL_DOUBLE_MIN 2.2250738585072013830902327173324e-308
55*433d6423SLionel Sambuc 
56*433d6423SLionel Sambuc /* Maximum subnormal double: (1 - 2^(-53)) * 2^(-1022) */
57*433d6423SLionel Sambuc #define SUBNORMAL_DOUBLE_MAX 2.2250738585072008890245868760859e-308
58*433d6423SLionel Sambuc 
59*433d6423SLionel Sambuc /* Minimum subnormal double: 2^(-52) * 2^(-1023) */
60*433d6423SLionel Sambuc #define SUBNORMAL_DOUBLE_MIN 4.9406564584124654417656879286822e-324
61*433d6423SLionel Sambuc 
test_fpclassify_values(void)62*433d6423SLionel Sambuc static void test_fpclassify_values(void)
63*433d6423SLionel Sambuc {
64*433d6423SLionel Sambuc 	double d;
65*433d6423SLionel Sambuc 	char negzero[] = { 0, 0, 0, 0, 0, 0, 0, 0x80 };
66*433d6423SLionel Sambuc 
67*433d6423SLionel Sambuc 	/* test some corner cases for fpclassify and signbit */
68*433d6423SLionel Sambuc 	test_fpclassify(INFINITY,             FP_INFINITE,    1);
69*433d6423SLionel Sambuc 	test_fpclassify(NAN,                  FP_NAN,         0);
70*433d6423SLionel Sambuc 	test_fpclassify(0,                    FP_ZERO,        0);
71*433d6423SLionel Sambuc 	test_fpclassify(1,                    FP_NORMAL,      1);
72*433d6423SLionel Sambuc 	test_fpclassify(NORMAL_DOUBLE_MAX,    FP_NORMAL,      1);
73*433d6423SLionel Sambuc 	test_fpclassify(NORMAL_DOUBLE_MIN,    FP_NORMAL,      1);
74*433d6423SLionel Sambuc 	test_fpclassify(SUBNORMAL_DOUBLE_MAX, FP_SUBNORMAL,   1);
75*433d6423SLionel Sambuc 	test_fpclassify(SUBNORMAL_DOUBLE_MIN, FP_SUBNORMAL,   1);
76*433d6423SLionel Sambuc 
77*433d6423SLionel Sambuc 	/*
78*433d6423SLionel Sambuc 	 * unfortunately the minus operator does not change the sign of zero,
79*433d6423SLionel Sambuc 	 * so a special case is needed to test it
80*433d6423SLionel Sambuc 	 */
81*433d6423SLionel Sambuc 	assert(sizeof(negzero) == sizeof(double));
82*433d6423SLionel Sambuc 	test_fpclassify(*(double *) negzero, FP_ZERO, 0);
83*433d6423SLionel Sambuc 	if (!signbit(*(double *) negzero)) e(4);
84*433d6423SLionel Sambuc 
85*433d6423SLionel Sambuc 	/* test other small numbers for fpclassify and signbit */
86*433d6423SLionel Sambuc 	d = 1;
87*433d6423SLionel Sambuc 	while (d >= NORMAL_DOUBLE_MIN)
88*433d6423SLionel Sambuc 	{
89*433d6423SLionel Sambuc 		test_fpclassify(d, FP_NORMAL, 1);
90*433d6423SLionel Sambuc 		d /= 10;
91*433d6423SLionel Sambuc 	}
92*433d6423SLionel Sambuc 	while (d >= SUBNORMAL_DOUBLE_MIN)
93*433d6423SLionel Sambuc 	{
94*433d6423SLionel Sambuc 		test_fpclassify(d, FP_SUBNORMAL, 1);
95*433d6423SLionel Sambuc 		d /= 10;
96*433d6423SLionel Sambuc 	}
97*433d6423SLionel Sambuc 	test_fpclassify(d, FP_ZERO, 0);
98*433d6423SLionel Sambuc 
99*433d6423SLionel Sambuc 	/* test other large numbers for fpclassify and signbit */
100*433d6423SLionel Sambuc 	d = 1;
101*433d6423SLionel Sambuc 	while (d <= NORMAL_DOUBLE_MAX / 10)
102*433d6423SLionel Sambuc 	{
103*433d6423SLionel Sambuc 		test_fpclassify(d, FP_NORMAL, 1);
104*433d6423SLionel Sambuc 		d *= 10;
105*433d6423SLionel Sambuc 	}
106*433d6423SLionel Sambuc }
107*433d6423SLionel Sambuc 
108*433d6423SLionel Sambuc /* expected rounding: up, down or identical */
109*433d6423SLionel Sambuc #define ROUND_EQ 1
110*433d6423SLionel Sambuc #define ROUND_DN 2
111*433d6423SLionel Sambuc #define ROUND_UP 3
112*433d6423SLionel Sambuc 
test_round_value_mode_func(double value,int mode,double (* func)(double),int exp)113*433d6423SLionel Sambuc static void test_round_value_mode_func(double value, int mode, double (*func)(double), int exp)
114*433d6423SLionel Sambuc {
115*433d6423SLionel Sambuc 	int mode_old;
116*433d6423SLionel Sambuc 	double rounded;
117*433d6423SLionel Sambuc 
118*433d6423SLionel Sambuc 	/* update and check rounding mode */
119*433d6423SLionel Sambuc 	mode_old = fegetround();
120*433d6423SLionel Sambuc 	fesetround(mode);
121*433d6423SLionel Sambuc 	if (fegetround() != mode) e(5);
122*433d6423SLionel Sambuc 
123*433d6423SLionel Sambuc 	/* perform rounding */
124*433d6423SLionel Sambuc 	rounded = func(value);
125*433d6423SLionel Sambuc 
126*433d6423SLionel Sambuc 	/* check direction of rounding */
127*433d6423SLionel Sambuc 	switch (exp)
128*433d6423SLionel Sambuc 	{
129*433d6423SLionel Sambuc 		case ROUND_EQ: if (rounded != value) e(6); break;
130*433d6423SLionel Sambuc 		case ROUND_DN: if (rounded >= value) e(7); break;
131*433d6423SLionel Sambuc 		case ROUND_UP: if (rounded <= value) e(8); break;
132*433d6423SLionel Sambuc 		default:       assert(0);
133*433d6423SLionel Sambuc 	}
134*433d6423SLionel Sambuc 
135*433d6423SLionel Sambuc 	/* check whether the number is sufficiently close */
136*433d6423SLionel Sambuc 	if (fabs(value - rounded) >= 1) e(9);
137*433d6423SLionel Sambuc 
138*433d6423SLionel Sambuc 	/* check whether the number is integer */
139*433d6423SLionel Sambuc 	if (remainder(rounded, 1)) e(10);
140*433d6423SLionel Sambuc 
141*433d6423SLionel Sambuc 	/* re-check and restore rounding mode */
142*433d6423SLionel Sambuc 	if (fegetround() != mode) e(11);
143*433d6423SLionel Sambuc 	fesetround(mode_old);
144*433d6423SLionel Sambuc }
145*433d6423SLionel Sambuc 
test_round_value_mode(double value,int mode,int exp_nearbyint,int exp_ceil,int exp_floor,int exp_trunc)146*433d6423SLionel Sambuc static void test_round_value_mode(double value, int mode, int exp_nearbyint,
147*433d6423SLionel Sambuc 	int exp_ceil, int exp_floor, int exp_trunc)
148*433d6423SLionel Sambuc {
149*433d6423SLionel Sambuc 	/* test both nearbyint and trunc */
150*433d6423SLionel Sambuc #if 0
151*433d6423SLionel Sambuc 	test_round_value_mode_func(value, mode, nearbyint, exp_nearbyint);
152*433d6423SLionel Sambuc #endif
153*433d6423SLionel Sambuc 	test_round_value_mode_func(value, mode, ceil,      exp_ceil);
154*433d6423SLionel Sambuc 	test_round_value_mode_func(value, mode, floor,     exp_floor);
155*433d6423SLionel Sambuc 	test_round_value_mode_func(value, mode, trunc,     exp_trunc);
156*433d6423SLionel Sambuc }
157*433d6423SLionel Sambuc 
test_round_value(double value,int exp_down,int exp_near,int exp_up,int exp_trunc)158*433d6423SLionel Sambuc static void test_round_value(double value, int exp_down, int exp_near, int exp_up, int exp_trunc)
159*433d6423SLionel Sambuc {
160*433d6423SLionel Sambuc 	/* test each rounding mode */
161*433d6423SLionel Sambuc 	test_round_value_mode(value, FE_DOWNWARD,   exp_down,  exp_up, exp_down, exp_trunc);
162*433d6423SLionel Sambuc 	test_round_value_mode(value, FE_TONEAREST,  exp_near,  exp_up, exp_down, exp_trunc);
163*433d6423SLionel Sambuc 	test_round_value_mode(value, FE_UPWARD,     exp_up,    exp_up, exp_down, exp_trunc);
164*433d6423SLionel Sambuc 	test_round_value_mode(value, FE_TOWARDZERO, exp_trunc, exp_up, exp_down, exp_trunc);
165*433d6423SLionel Sambuc }
166*433d6423SLionel Sambuc 
test_round_values(void)167*433d6423SLionel Sambuc static void test_round_values(void)
168*433d6423SLionel Sambuc {
169*433d6423SLionel Sambuc 	int i;
170*433d6423SLionel Sambuc 
171*433d6423SLionel Sambuc 	/* test various values */
172*433d6423SLionel Sambuc 	for (i = -100000; i < 100000; i++)
173*433d6423SLionel Sambuc 	{
174*433d6423SLionel Sambuc 		test_round_value(i + 0.00, ROUND_EQ, ROUND_EQ,                      ROUND_EQ, ROUND_EQ);
175*433d6423SLionel Sambuc 		test_round_value(i + 0.25, ROUND_DN, ROUND_DN,                      ROUND_UP, (i >= 0) ? ROUND_DN : ROUND_UP);
176*433d6423SLionel Sambuc 		test_round_value(i + 0.50, ROUND_DN, (i % 2) ? ROUND_UP : ROUND_DN, ROUND_UP, (i >= 0) ? ROUND_DN : ROUND_UP);
177*433d6423SLionel Sambuc 		test_round_value(i + 0.75, ROUND_DN, ROUND_UP,                      ROUND_UP, (i >= 0) ? ROUND_DN : ROUND_UP);
178*433d6423SLionel Sambuc 	}
179*433d6423SLionel Sambuc }
180*433d6423SLionel Sambuc 
test_remainder_value(double x,double y)181*433d6423SLionel Sambuc static void test_remainder_value(double x, double y)
182*433d6423SLionel Sambuc {
183*433d6423SLionel Sambuc 	int mode_old;
184*433d6423SLionel Sambuc 	double r1, r2;
185*433d6423SLionel Sambuc 
186*433d6423SLionel Sambuc 	assert(y != 0);
187*433d6423SLionel Sambuc 
188*433d6423SLionel Sambuc 	/* compute remainder using the function */
189*433d6423SLionel Sambuc 	r1 = remainder(x, y);
190*433d6423SLionel Sambuc 
191*433d6423SLionel Sambuc 	/* compute remainder using alternative approach */
192*433d6423SLionel Sambuc 	mode_old = fegetround();
193*433d6423SLionel Sambuc 	fesetround(FE_TONEAREST);
194*433d6423SLionel Sambuc 	r2 = x - rint(x / y) * y;
195*433d6423SLionel Sambuc 	fesetround(mode_old);
196*433d6423SLionel Sambuc 
197*433d6423SLionel Sambuc 	/* Compare results */
198*433d6423SLionel Sambuc 	if (fabs(r1 - r2) > EPSILON && fabs(r1 + r2) > EPSILON)
199*433d6423SLionel Sambuc 	{
200*433d6423SLionel Sambuc 		printf("%.20g != %.20g\n", r1, r2);
201*433d6423SLionel Sambuc 		e(13);
202*433d6423SLionel Sambuc 	}
203*433d6423SLionel Sambuc }
204*433d6423SLionel Sambuc 
test_remainder_values_y(double x)205*433d6423SLionel Sambuc static void test_remainder_values_y(double x)
206*433d6423SLionel Sambuc {
207*433d6423SLionel Sambuc 	int i, j;
208*433d6423SLionel Sambuc 
209*433d6423SLionel Sambuc 	/* try various rational and transcendental values for y (except zero) */
210*433d6423SLionel Sambuc 	for (i = -50; i <= 50; i++)
211*433d6423SLionel Sambuc 		if (i != 0)
212*433d6423SLionel Sambuc 			for (j = 1; j < 10; j++)
213*433d6423SLionel Sambuc 			{
214*433d6423SLionel Sambuc 				test_remainder_value(x, (double) i / (double) j);
215*433d6423SLionel Sambuc 				test_remainder_value(x, i * M_E + j * M_PI);
216*433d6423SLionel Sambuc 			}
217*433d6423SLionel Sambuc }
218*433d6423SLionel Sambuc 
test_remainder_values_xy(void)219*433d6423SLionel Sambuc static void test_remainder_values_xy(void)
220*433d6423SLionel Sambuc {
221*433d6423SLionel Sambuc 	int i, j;
222*433d6423SLionel Sambuc 
223*433d6423SLionel Sambuc 	/* try various rational and transcendental values for x */
224*433d6423SLionel Sambuc 	for (i = -50; i <= 50; i++)
225*433d6423SLionel Sambuc 		for (j = 1; j < 10; j++)
226*433d6423SLionel Sambuc 		{
227*433d6423SLionel Sambuc 			test_remainder_values_y((double) i / (double) j);
228*433d6423SLionel Sambuc 			test_remainder_values_y(i * M_E + j * M_PI);
229*433d6423SLionel Sambuc 		}
230*433d6423SLionel Sambuc }
231*433d6423SLionel Sambuc 
main(int argc,char ** argv)232*433d6423SLionel Sambuc int main(int argc, char **argv)
233*433d6423SLionel Sambuc {
234*433d6423SLionel Sambuc 	fenv_t fenv;
235*433d6423SLionel Sambuc 	int i;
236*433d6423SLionel Sambuc 
237*433d6423SLionel Sambuc 	start(47);
238*433d6423SLionel Sambuc 
239*433d6423SLionel Sambuc 	/* no FPU errors, please */
240*433d6423SLionel Sambuc 	if (feholdexcept(&fenv) < 0) e(14);
241*433d6423SLionel Sambuc 
242*433d6423SLionel Sambuc 	/* some signals count as errors */
243*433d6423SLionel Sambuc 	for (i = 0; i < _NSIG; i++)
244*433d6423SLionel Sambuc 		if (i != SIGINT && i != SIGTERM && i != SIGKILL)
245*433d6423SLionel Sambuc 			signal(i, signal_handler);
246*433d6423SLionel Sambuc 
247*433d6423SLionel Sambuc 	/* test various floating point support functions */
248*433d6423SLionel Sambuc 	test_fpclassify_values();
249*433d6423SLionel Sambuc 	test_remainder_values_xy();
250*433d6423SLionel Sambuc 	test_round_values();
251*433d6423SLionel Sambuc 	quit();
252*433d6423SLionel Sambuc 	return -1;
253*433d6423SLionel Sambuc }
254