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