1 /* 2 * Written by Maya Rashish <maya@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 for (unsigned int i = 0; i < __arraycount(values2); i++) { 172 received = nexttoward(values2[i].input, values2[i].toward); 173 if (values2[i].input < values2[i].toward) { 174 res = (received > values2[i].input); 175 } else { 176 res = (received < values2[i].input); 177 } 178 ATF_CHECK_MSG( 179 res && (fabs(received - values2[i].expected) < EPSILON), 180 "nexttoward() rounding wrong, difference too large\n" 181 "input: %f (index %d): got %f, expected %f, res %d\n", 182 values2[i].input, i, received, values2[i].expected, res); 183 } 184 } 185 186 ATF_TP_ADD_TCS(tp) 187 { 188 189 ATF_TP_ADD_TC(tp, fe_round); 190 ATF_TP_ADD_TC(tp, fe_nearbyint); 191 ATF_TP_ADD_TC(tp, fe_nextafter); 192 ATF_TP_ADD_TC(tp, fe_nexttoward); 193 194 return atf_no_error(); 195 } 196 #else 197 ATF_TC(t_nofe_round); 198 199 ATF_TC_HEAD(t_nofe_round, tc) 200 { 201 atf_tc_set_md_var(tc, "descr", 202 "dummy test case - no fenv.h support"); 203 } 204 205 ATF_TC_BODY(t_nofe_round, tc) 206 { 207 atf_tc_skip("no fenv.h support on this architecture"); 208 } 209 210 ATF_TC(t_nofe_nearbyint); 211 212 ATF_TC_HEAD(t_nofe_nearbyint, tc) 213 { 214 atf_tc_set_md_var(tc, "descr", 215 "dummy test case - no fenv.h support"); 216 } 217 218 ATF_TC_BODY(t_nofe_nearbyint, tc) 219 { 220 atf_tc_skip("no fenv.h support on this architecture"); 221 } 222 223 ATF_TC(t_nofe_nextafter); 224 225 ATF_TC_HEAD(t_nofe_nextafter, tc) 226 { 227 atf_tc_set_md_var(tc, "descr", 228 "dummy test case - no fenv.h support"); 229 } 230 231 ATF_TC_BODY(t_nofe_nextafter, tc) 232 { 233 atf_tc_skip("no fenv.h support on this architecture"); 234 } 235 236 ATF_TC(t_nofe_nexttoward); 237 238 ATF_TC_HEAD(t_nofe_nexttoward, tc) 239 { 240 atf_tc_set_md_var(tc, "descr", 241 "dummy test case - no fenv.h support"); 242 } 243 244 ATF_TC_BODY(t_nofe_nexttoward, tc) 245 { 246 atf_tc_skip("no fenv.h support on this architecture"); 247 } 248 249 ATF_TP_ADD_TCS(tp) 250 { 251 ATF_TP_ADD_TC(tp, t_nofe_round); 252 ATF_TP_ADD_TC(tp, t_nofe_nearbyint); 253 ATF_TP_ADD_TC(tp, t_nofe_nextafter); 254 ATF_TP_ADD_TC(tp, t_nofe_nexttoward); 255 return atf_no_error(); 256 } 257 258 #endif 259