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