8 #include <machine/frame.h>
14 /* maximum allowed FP difference for our tests */
15 #define EPSILON 0.00000000023283064365386962890625 /* 2^(-32) */
17 #define ERR(x, y) e(__LINE__, (x), (y))
19 static void signal_handler(int signum
)
21 struct sigframe_sigcontext
*sigframe
;
24 sigframe
= (struct sigframe_sigcontext
*) ((char *) &signum
-
25 (char *) &((struct sigframe_sigcontext
*) NULL
)->sf_signum
);
26 printf("Signal %d at 0x%x\n", signum
, sigframe
->sf_scp
->sc_eip
);
32 /* handle signa again next time */
33 signal(signum
, signal_handler
);
36 static void test_fpclassify(double value
, int class, int test_sign
)
39 if (fpclassify(value
) != class) e(101);
42 if (fpclassify(-value
) != class) e(102);
45 if (signbit(value
)) e(103);
46 if (!signbit(-value
)) e(104);
50 /* Maximum normal double: (2 - 2^(-53)) * 2^1023 */
51 #define NORMAL_DOUBLE_MAX 1.797693134862315708145274237317e+308
53 /* Minimum normal double: 2^(-1022) */
54 #define NORMAL_DOUBLE_MIN 2.2250738585072013830902327173324e-308
56 /* Maximum subnormal double: (1 - 2^(-53)) * 2^(-1022) */
57 #define SUBNORMAL_DOUBLE_MAX 2.2250738585072008890245868760859e-308
59 /* Minimum subnormal double: 2^(-52) * 2^(-1023) */
60 #define SUBNORMAL_DOUBLE_MIN 4.9406564584124654417656879286822e-324
62 static void test_fpclassify_values(void)
65 char negzero
[] = { 0, 0, 0, 0, 0, 0, 0, 0x80 };
67 /* test some corner cases for fpclassify and signbit */
68 test_fpclassify(INFINITY
, FP_INFINITE
, 1);
69 test_fpclassify(NAN
, FP_NAN
, 0);
70 test_fpclassify(0, FP_ZERO
, 0);
71 test_fpclassify(1, FP_NORMAL
, 1);
72 test_fpclassify(NORMAL_DOUBLE_MAX
, FP_NORMAL
, 1);
73 test_fpclassify(NORMAL_DOUBLE_MIN
, FP_NORMAL
, 1);
74 test_fpclassify(SUBNORMAL_DOUBLE_MAX
, FP_SUBNORMAL
, 1);
75 test_fpclassify(SUBNORMAL_DOUBLE_MIN
, FP_SUBNORMAL
, 1);
78 * unfortunately the minus operator does not change the sign of zero,
79 * so a special case is needed to test it
81 assert(sizeof(negzero
) == sizeof(double));
82 test_fpclassify(*(double *) negzero
, FP_ZERO
, 0);
83 if (!signbit(*(double *) negzero
)) e(4);
85 /* test other small numbers for fpclassify and signbit */
87 while (d
>= NORMAL_DOUBLE_MIN
)
89 test_fpclassify(d
, FP_NORMAL
, 1);
92 while (d
>= SUBNORMAL_DOUBLE_MIN
)
94 test_fpclassify(d
, FP_SUBNORMAL
, 1);
97 test_fpclassify(d
, FP_ZERO
, 0);
99 /* test other large numbers for fpclassify and signbit */
101 while (d
<= NORMAL_DOUBLE_MAX
/ 10)
103 test_fpclassify(d
, FP_NORMAL
, 1);
108 /* expected rounding: up, down or identical */
113 static void test_round_value_mode_func(double value
, int mode
, double (*func
)(double), int exp
)
118 /* update and check rounding mode */
119 mode_old
= fegetround();
121 if (fegetround() != mode
) e(5);
123 /* perform rounding */
124 rounded
= func(value
);
126 /* check direction of rounding */
129 case ROUND_EQ
: if (rounded
!= value
) e(6); break;
130 case ROUND_DN
: if (rounded
>= value
) e(7); break;
131 case ROUND_UP
: if (rounded
<= value
) e(8); break;
135 /* check whether the number is sufficiently close */
136 if (fabs(value
- rounded
) >= 1) e(9);
138 /* check whether the number is integer */
139 if (remainder(rounded
, 1)) e(10);
141 /* re-check and restore rounding mode */
142 if (fegetround() != mode
) e(11);
143 fesetround(mode_old
);
146 static void test_round_value_mode(double value
, int mode
, int exp_nearbyint
,
147 int exp_ceil
, int exp_floor
, int exp_trunc
)
149 /* test both nearbyint and trunc */
151 test_round_value_mode_func(value
, mode
, nearbyint
, exp_nearbyint
);
153 test_round_value_mode_func(value
, mode
, ceil
, exp_ceil
);
154 test_round_value_mode_func(value
, mode
, floor
, exp_floor
);
155 test_round_value_mode_func(value
, mode
, trunc
, exp_trunc
);
158 static void test_round_value(double value
, int exp_down
, int exp_near
, int exp_up
, int exp_trunc
)
160 /* test each rounding mode */
161 test_round_value_mode(value
, FE_DOWNWARD
, exp_down
, exp_up
, exp_down
, exp_trunc
);
162 test_round_value_mode(value
, FE_TONEAREST
, exp_near
, exp_up
, exp_down
, exp_trunc
);
163 test_round_value_mode(value
, FE_UPWARD
, exp_up
, exp_up
, exp_down
, exp_trunc
);
164 test_round_value_mode(value
, FE_TOWARDZERO
, exp_trunc
, exp_up
, exp_down
, exp_trunc
);
167 static void test_round_values(void)
171 /* test various values */
172 for (i
= -100000; i
< 100000; i
++)
174 test_round_value(i
+ 0.00, ROUND_EQ
, ROUND_EQ
, ROUND_EQ
, ROUND_EQ
);
175 test_round_value(i
+ 0.25, ROUND_DN
, ROUND_DN
, ROUND_UP
, (i
>= 0) ? ROUND_DN
: ROUND_UP
);
176 test_round_value(i
+ 0.50, ROUND_DN
, (i
% 2) ? ROUND_UP
: ROUND_DN
, ROUND_UP
, (i
>= 0) ? ROUND_DN
: ROUND_UP
);
177 test_round_value(i
+ 0.75, ROUND_DN
, ROUND_UP
, ROUND_UP
, (i
>= 0) ? ROUND_DN
: ROUND_UP
);
181 static void test_remainder_value(double x
, double y
)
188 /* compute remainder using the function */
189 r1
= remainder(x
, y
);
191 /* compute remainder using alternative approach */
192 mode_old
= fegetround();
193 fesetround(FE_TONEAREST
);
194 r2
= x
- rint(x
/ y
) * y
;
195 fesetround(mode_old
);
197 /* Compare results */
198 if (fabs(r1
- r2
) > EPSILON
&& fabs(r1
+ r2
) > EPSILON
)
200 printf("%.20g != %.20g\n", r1
, r2
);
205 static void test_remainder_values_y(double x
)
209 /* try various rational and transcendental values for y (except zero) */
210 for (i
= -50; i
<= 50; i
++)
212 for (j
= 1; j
< 10; j
++)
214 test_remainder_value(x
, (double) i
/ (double) j
);
215 test_remainder_value(x
, i
* M_E
+ j
* M_PI
);
219 static void test_remainder_values_xy(void)
223 /* try various rational and transcendental values for x */
224 for (i
= -50; i
<= 50; i
++)
225 for (j
= 1; j
< 10; j
++)
227 test_remainder_values_y((double) i
/ (double) j
);
228 test_remainder_values_y(i
* M_E
+ j
* M_PI
);
232 int main(int argc
, char **argv
)
239 /* no FPU errors, please */
240 if (feholdexcept(&fenv
) < 0) e(14);
242 /* some signals count as errors */
243 for (i
= 0; i
< _NSIG
; i
++)
244 if (i
!= SIGINT
&& i
!= SIGTERM
&& i
!= SIGKILL
)
245 signal(i
, signal_handler
);
247 /* test various floating point support functions */
248 test_fpclassify_values();
249 test_remainder_values_xy();