Home | History | Annotate | Line # | Download | only in libm
t_fe_round.c revision 1.6
      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 ATF_TP_ADD_TCS(tp)
    126 {
    127 
    128 	ATF_TP_ADD_TC(tp, fe_round);
    129 	ATF_TP_ADD_TC(tp, fe_nearbyint);
    130 
    131 	return atf_no_error();
    132 }
    133 #else
    134 ATF_TC(t_nofe_round);
    135 
    136 ATF_TC_HEAD(t_nofe_round, tc)
    137 {
    138 	atf_tc_set_md_var(tc, "descr",
    139 	    "dummy test case - no fenv.h support");
    140 }
    141 
    142 
    143 ATF_TC_BODY(t_nofe_round, tc)
    144 {
    145 	atf_tc_skip("no fenv.h support on this architecture");
    146 }
    147 
    148 ATF_TC(t_nofe_nearbyint);
    149 
    150 ATF_TC_HEAD(t_nofe_nearbyint, tc)
    151 {
    152 	atf_tc_set_md_var(tc, "descr",
    153 	    "dummy test case - no fenv.h support");
    154 }
    155 
    156 ATF_TC_BODY(t_nofe_nearbyint, tc)
    157 {
    158 	atf_tc_skip("no fenv.h support on this architecture");
    159 }
    160 
    161 
    162 ATF_TP_ADD_TCS(tp)
    163 {
    164 	ATF_TP_ADD_TC(tp, t_nofe_round);
    165 	ATF_TP_ADD_TC(tp, t_nofe_nearbyint);
    166 	return atf_no_error();
    167 }
    168 
    169 #endif
    170