Home | History | Annotate | Line # | Download | only in libm
t_fe_round.c revision 1.8
      1 /*
      2  * Written by Maya Rashish <maya (at) NetBSD.org>
      3  * Public domain.
      4  *
      5  * Testing IEEE-754 rounding modes (and lrint)
      6  */
      7 
      8 #include <atf-c.h>
      9 #include <fenv.h>
     10 #ifdef __HAVE_FENV
     11 #include <math.h>
     12 #include <stdio.h>
     13 #include <stdlib.h>
     14 
     15 /*#pragma STDC FENV_ACCESS ON gcc?? */
     16 
     17 #define INT 9223L
     18 
     19 #define EPSILON 0.001
     20 
     21 static const struct {
     22 	int round_mode;
     23 	double input;
     24 	long int expected;
     25 } values[] = {
     26 	{ FE_DOWNWARD,		3.7,		3},
     27 	{ FE_DOWNWARD,		-3.7,		-4},
     28 	{ FE_DOWNWARD,		+0,		0},
     29 	{ FE_DOWNWARD,		-INT-0.01,	-INT-1},
     30 	{ FE_DOWNWARD,		+INT-0.01,	INT-1},
     31 	{ FE_DOWNWARD,		-INT+0.01,	-INT},
     32 	{ FE_DOWNWARD,		+INT+0.01,	INT},
     33 #if 0 /* cpu bugs? */
     34 	{ FE_DOWNWARD,		-0,		-1},
     35 
     36 	{ FE_UPWARD,		+0,		1},
     37 #endif
     38 	{ FE_UPWARD,		-0,		0},
     39 	{ FE_UPWARD,		-123.7,		-123},
     40 	{ FE_UPWARD,		123.999,	124},
     41 	{ FE_UPWARD,		-INT-0.01,	-INT},
     42 	{ FE_UPWARD,		+INT-0.01,	INT},
     43 	{ FE_UPWARD,		-INT+0.01,	-INT+1},
     44 	{ FE_UPWARD,		+INT+0.01,	INT+1},
     45 
     46 	{ FE_TOWARDZERO,	1.99,		1},
     47 	{ FE_TOWARDZERO,	-1.99,		-1},
     48 	{ FE_TOWARDZERO,	0.2,		0},
     49 	{ FE_TOWARDZERO,	INT+0.01,	INT},
     50 	{ FE_TOWARDZERO,	INT-0.01,	INT - 1},
     51 	{ FE_TOWARDZERO,	-INT+0.01,	-INT + 1},
     52 	{ FE_TOWARDZERO,	+0,		0},
     53 	{ FE_TOWARDZERO,	-0,		0},
     54 
     55 	{ FE_TONEAREST,		-INT-0.01,	-INT},
     56 	{ FE_TONEAREST,		+INT-0.01,	INT},
     57 	{ FE_TONEAREST,		-INT+0.01,	-INT},
     58 	{ FE_TONEAREST,		+INT+0.01,	INT},
     59 	{ FE_TONEAREST,		-INT-0.501,	-INT-1},
     60 	{ FE_TONEAREST,		+INT-0.501,	INT-1},
     61 	{ FE_TONEAREST,		-INT+0.501,	-INT+1},
     62 	{ FE_TONEAREST,		+INT+0.501,	INT+1},
     63 	{ FE_TONEAREST,		+0,		0},
     64 	{ FE_TONEAREST,		-0,		0},
     65 };
     66 
     67 ATF_TC(fe_round);
     68 ATF_TC_HEAD(fe_round, tc)
     69 {
     70 	atf_tc_set_md_var(tc, "descr","Checking IEEE 754 rounding modes using lrint");
     71 }
     72 
     73 ATF_TC_BODY(fe_round, tc)
     74 {
     75 	long int received;
     76 
     77 	for (unsigned int i = 0; i < __arraycount(values); i++) {
     78 		fesetround(values[i].round_mode);
     79 
     80 		received = lrint(values[i].input);
     81 		ATF_CHECK_MSG(
     82 		    (labs(received - values[i].expected) < EPSILON),
     83 		    "lrint rounding wrong, difference too large\n"
     84 		    "input: %f (index %d): got %ld, expected %ld\n",
     85 		    values[i].input, i, received, values[i].expected);
     86 
     87 		/* Do we get the same rounding mode out? */
     88 		ATF_CHECK_MSG(
     89 		    (fegetround() == values[i].round_mode),
     90 		    "Didn't get the same rounding mode out!\n"
     91 		    "(index %d) fed in %d rounding mode, got %d out\n",
     92 		    i, values[i].round_mode, fegetround());
     93 	}
     94 }
     95 
     96 ATF_TC(fe_nearbyint);
     97 ATF_TC_HEAD(fe_nearbyint, tc)
     98 {
     99 	atf_tc_set_md_var(tc, "descr","Checking IEEE 754 rounding modes using nearbyint");
    100 }
    101 
    102 ATF_TC_BODY(fe_nearbyint, tc)
    103 {
    104 	double received;
    105 
    106 	for (unsigned int i = 0; i < __arraycount(values); i++) {
    107 		fesetround(values[i].round_mode);
    108 
    109 		received = nearbyint(values[i].input);
    110 		ATF_CHECK_MSG(
    111 		    (fabs(received - values[i].expected) < EPSILON),
    112 		    "nearbyint rounding wrong, difference too large\n"
    113 		    "input: %f (index %d): got %f, expected %ld\n",
    114 		    values[i].input, i, received, values[i].expected);
    115 
    116 		/* Do we get the same rounding mode out? */
    117 		ATF_CHECK_MSG(
    118 		    (fegetround() == values[i].round_mode),
    119 		    "Didn't get the same rounding mode out!\n"
    120 		    "(index %d) fed in %d rounding mode, got %d out\n",
    121 		    i, values[i].round_mode, fegetround());
    122 	}
    123 }
    124 
    125 static const struct {
    126 	double input;
    127 	double toward;
    128 	double expected;
    129 } values2[] = {
    130 	{ 10.0, 11.0, 10.0 },
    131 	{ -5.0, -6.0, -5.0 },
    132 };
    133 
    134 ATF_TC(fe_nextafter);
    135 ATF_TC_HEAD(fe_nextafter, tc)
    136 {
    137 	atf_tc_set_md_var(tc, "descr", "Checking IEEE 754 rounding using nextafter()");
    138 }
    139 
    140 ATF_TC_BODY(fe_nextafter, tc)
    141 {
    142 	double received;
    143 	int res;
    144 
    145 	for (unsigned int i = 0; i < __arraycount(values2); i++) {
    146 		received = nextafter(values2[i].input, values2[i].toward);
    147 		if (values2[i].input < values2[i].toward) {
    148 			res = (received > values2[i].input);
    149 		} else {
    150 			res = (received < values2[i].input);
    151 		}
    152 		ATF_CHECK_MSG(
    153 			res && (fabs(received - values2[i].expected) < EPSILON),
    154 			"nextafter() rounding wrong, difference too large\n"
    155 			"input: %f (index %d): got %f, expected %f, res %d\n",
    156 			values2[i].input, i, received, values2[i].expected, res);
    157 	}
    158 }
    159 
    160 ATF_TC(fe_nexttoward);
    161 ATF_TC_HEAD(fe_nexttoward, tc)
    162 {
    163 	atf_tc_set_md_var(tc, "descr", "Checking IEEE 754 rounding using nexttoward()");
    164 }
    165 
    166 ATF_TC_BODY(fe_nexttoward, tc)
    167 {
    168 	double received;
    169 	int res;
    170 
    171 #if defined(_LP64) && (defined(__mips__) || defined(__arm__))
    172 	ATF_CHECK_MSG(0, "nexttoward not supported yet on mips64 or aarch64");
    173 #else
    174 	for (unsigned int i = 0; i < __arraycount(values2); i++) {
    175 		received = nexttoward(values2[i].input, values2[i].toward);
    176 		if (values2[i].input < values2[i].toward) {
    177 			res = (received > values2[i].input);
    178 		} else {
    179 			res = (received < values2[i].input);
    180 		}
    181 		ATF_CHECK_MSG(
    182 			res && (fabs(received - values2[i].expected) < EPSILON),
    183 			"nexttoward() rounding wrong, difference too large\n"
    184 			"input: %f (index %d): got %f, expected %f, res %d\n",
    185 			values2[i].input, i, received, values2[i].expected, res);
    186 	}
    187 #endif
    188 }
    189 
    190 ATF_TP_ADD_TCS(tp)
    191 {
    192 
    193 	ATF_TP_ADD_TC(tp, fe_round);
    194 	ATF_TP_ADD_TC(tp, fe_nearbyint);
    195 	ATF_TP_ADD_TC(tp, fe_nextafter);
    196 	ATF_TP_ADD_TC(tp, fe_nexttoward);
    197 
    198 	return atf_no_error();
    199 }
    200 #else
    201 ATF_TC(t_nofe_round);
    202 
    203 ATF_TC_HEAD(t_nofe_round, tc)
    204 {
    205 	atf_tc_set_md_var(tc, "descr",
    206 	    "dummy test case - no fenv.h support");
    207 }
    208 
    209 ATF_TC_BODY(t_nofe_round, tc)
    210 {
    211 	atf_tc_skip("no fenv.h support on this architecture");
    212 }
    213 
    214 ATF_TC(t_nofe_nearbyint);
    215 
    216 ATF_TC_HEAD(t_nofe_nearbyint, tc)
    217 {
    218 	atf_tc_set_md_var(tc, "descr",
    219 	    "dummy test case - no fenv.h support");
    220 }
    221 
    222 ATF_TC_BODY(t_nofe_nearbyint, tc)
    223 {
    224 	atf_tc_skip("no fenv.h support on this architecture");
    225 }
    226 
    227 ATF_TC(t_nofe_nextafter);
    228 
    229 ATF_TC_HEAD(t_nofe_nextafter, tc)
    230 {
    231 	atf_tc_set_md_var(tc, "descr",
    232 	    "dummy test case - no fenv.h support");
    233 }
    234 
    235 ATF_TC_BODY(t_nofe_nextafter, tc)
    236 {
    237 	atf_tc_skip("no fenv.h support on this architecture");
    238 }
    239 
    240 ATF_TC(t_nofe_nexttoward);
    241 
    242 ATF_TC_HEAD(t_nofe_nexttoward, tc)
    243 {
    244 	atf_tc_set_md_var(tc, "descr",
    245 	    "dummy test case - no fenv.h support");
    246 }
    247 
    248 ATF_TC_BODY(t_nofe_nexttoward, tc)
    249 {
    250 	atf_tc_skip("no fenv.h support on this architecture");
    251 }
    252 
    253 ATF_TP_ADD_TCS(tp)
    254 {
    255 	ATF_TP_ADD_TC(tp, t_nofe_round);
    256 	ATF_TP_ADD_TC(tp, t_nofe_nearbyint);
    257 	ATF_TP_ADD_TC(tp, t_nofe_nextafter);
    258 	ATF_TP_ADD_TC(tp, t_nofe_nexttoward);
    259 	return atf_no_error();
    260 }
    261 
    262 #endif
    263