Home | History | Annotate | Line # | Download | only in libm
t_fe_round.c revision 1.13
      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.12       kre #include <stdint.h>
     13   1.1      maya #include <stdio.h>
     14   1.1      maya #include <stdlib.h>
     15   1.1      maya 
     16   1.1      maya /*#pragma STDC FENV_ACCESS ON gcc?? */
     17   1.1      maya 
     18   1.1      maya #define INT 9223L
     19   1.1      maya 
     20   1.1      maya #define EPSILON 0.001
     21   1.1      maya 
     22  1.10  riastrad static const char *
     23  1.10  riastrad rmname(int rm)
     24  1.10  riastrad {
     25  1.10  riastrad 	switch (rm) {
     26  1.10  riastrad 	case FE_TOWARDZERO:
     27  1.10  riastrad 		return "FE_TOWARDZERO";
     28  1.10  riastrad 	case FE_DOWNWARD:
     29  1.10  riastrad 		return "FE_DOWNWARD";
     30  1.10  riastrad 	case FE_UPWARD:
     31  1.10  riastrad 		return "FE_UPWARD";
     32  1.10  riastrad 	case FE_TONEAREST:
     33  1.10  riastrad 		return "FE_TONEAREST";
     34  1.10  riastrad 	default:
     35  1.10  riastrad 		return "unknown";
     36  1.10  riastrad 	}
     37  1.10  riastrad }
     38  1.10  riastrad 
     39   1.1      maya static const struct {
     40   1.1      maya 	int round_mode;
     41   1.1      maya 	double input;
     42   1.1      maya 	long int expected;
     43   1.1      maya } values[] = {
     44   1.1      maya 	{ FE_DOWNWARD,		3.7,		3},
     45   1.1      maya 	{ FE_DOWNWARD,		-3.7,		-4},
     46   1.1      maya 	{ FE_DOWNWARD,		+0,		0},
     47   1.1      maya 	{ FE_DOWNWARD,		-INT-0.01,	-INT-1},
     48   1.1      maya 	{ FE_DOWNWARD,		+INT-0.01,	INT-1},
     49   1.1      maya 	{ FE_DOWNWARD,		-INT+0.01,	-INT},
     50   1.1      maya 	{ FE_DOWNWARD,		+INT+0.01,	INT},
     51   1.1      maya #if 0 /* cpu bugs? */
     52   1.1      maya 	{ FE_DOWNWARD,		-0,		-1},
     53   1.1      maya 
     54   1.1      maya 	{ FE_UPWARD,		+0,		1},
     55   1.1      maya #endif
     56   1.1      maya 	{ FE_UPWARD,		-0,		0},
     57   1.1      maya 	{ FE_UPWARD,		-123.7,		-123},
     58   1.1      maya 	{ FE_UPWARD,		123.999,	124},
     59   1.1      maya 	{ FE_UPWARD,		-INT-0.01,	-INT},
     60   1.1      maya 	{ FE_UPWARD,		+INT-0.01,	INT},
     61   1.1      maya 	{ FE_UPWARD,		-INT+0.01,	-INT+1},
     62   1.1      maya 	{ FE_UPWARD,		+INT+0.01,	INT+1},
     63   1.1      maya 
     64   1.1      maya 	{ FE_TOWARDZERO,	1.99,		1},
     65   1.1      maya 	{ FE_TOWARDZERO,	-1.99,		-1},
     66   1.1      maya 	{ FE_TOWARDZERO,	0.2,		0},
     67   1.1      maya 	{ FE_TOWARDZERO,	INT+0.01,	INT},
     68   1.1      maya 	{ FE_TOWARDZERO,	INT-0.01,	INT - 1},
     69   1.1      maya 	{ FE_TOWARDZERO,	-INT+0.01,	-INT + 1},
     70   1.1      maya 	{ FE_TOWARDZERO,	+0,		0},
     71   1.1      maya 	{ FE_TOWARDZERO,	-0,		0},
     72   1.1      maya 
     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.01,	INT},
     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,		+INT+0.501,	INT+1},
     81   1.1      maya 	{ FE_TONEAREST,		+0,		0},
     82   1.1      maya 	{ FE_TONEAREST,		-0,		0},
     83   1.1      maya };
     84   1.1      maya 
     85   1.1      maya ATF_TC(fe_round);
     86   1.1      maya ATF_TC_HEAD(fe_round, tc)
     87   1.1      maya {
     88   1.1      maya 	atf_tc_set_md_var(tc, "descr","Checking IEEE 754 rounding modes using lrint");
     89   1.1      maya }
     90   1.1      maya 
     91   1.1      maya ATF_TC_BODY(fe_round, tc)
     92   1.1      maya {
     93   1.1      maya 	long int received;
     94   1.1      maya 
     95   1.1      maya 	for (unsigned int i = 0; i < __arraycount(values); i++) {
     96   1.1      maya 		fesetround(values[i].round_mode);
     97   1.1      maya 
     98   1.1      maya 		received = lrint(values[i].input);
     99   1.1      maya 		ATF_CHECK_MSG(
    100   1.2      maya 		    (labs(received - values[i].expected) < EPSILON),
    101   1.1      maya 		    "lrint rounding wrong, difference too large\n"
    102   1.1      maya 		    "input: %f (index %d): got %ld, expected %ld\n",
    103   1.1      maya 		    values[i].input, i, received, values[i].expected);
    104   1.1      maya 
    105   1.1      maya 		/* Do we get the same rounding mode out? */
    106   1.1      maya 		ATF_CHECK_MSG(
    107   1.1      maya 		    (fegetround() == values[i].round_mode),
    108   1.1      maya 		    "Didn't get the same rounding mode out!\n"
    109   1.1      maya 		    "(index %d) fed in %d rounding mode, got %d out\n",
    110   1.3        he 		    i, values[i].round_mode, fegetround());
    111   1.1      maya 	}
    112   1.1      maya }
    113   1.1      maya 
    114   1.6        he ATF_TC(fe_nearbyint);
    115   1.6        he ATF_TC_HEAD(fe_nearbyint, tc)
    116   1.6        he {
    117  1.10  riastrad 	atf_tc_set_md_var(tc, "descr",
    118  1.10  riastrad 	    "Checking IEEE 754 rounding modes using nearbyint");
    119   1.6        he }
    120   1.6        he 
    121   1.6        he ATF_TC_BODY(fe_nearbyint, tc)
    122   1.6        he {
    123  1.10  riastrad 	double received, ipart, fpart;
    124   1.6        he 
    125   1.6        he 	for (unsigned int i = 0; i < __arraycount(values); i++) {
    126   1.6        he 		fesetround(values[i].round_mode);
    127   1.6        he 
    128   1.6        he 		received = nearbyint(values[i].input);
    129  1.10  riastrad 		fpart = modf(received, &ipart);
    130  1.10  riastrad 		ATF_CHECK_MSG(fpart == 0,
    131  1.10  riastrad 		    "%s nearbyint(%f) has fractional part %f",
    132  1.10  riastrad 		    rmname(values[i].round_mode), values[i].input, fpart);
    133  1.10  riastrad 		ATF_CHECK_MSG((long int)received == values[i].expected,
    134  1.10  riastrad 		    "%s [%u] nearbyint(%f) got %f, expected %ld\n",
    135  1.10  riastrad 		    rmname(values[i].round_mode),
    136  1.10  riastrad 		    i, values[i].input, received, values[i].expected);
    137   1.6        he 
    138   1.6        he 		/* Do we get the same rounding mode out? */
    139  1.10  riastrad 		ATF_CHECK_MSG(fegetround() == values[i].round_mode,
    140  1.10  riastrad 		    "[%u] set %d (%s), got %d (%s)",
    141  1.10  riastrad 		    i,
    142  1.10  riastrad 		    values[i].round_mode, rmname(values[i].round_mode),
    143  1.10  riastrad 		    fegetround(), rmname(fegetround()));
    144   1.6        he 	}
    145   1.6        he }
    146   1.6        he 
    147  1.11  riastrad #ifdef __HAVE_LONG_DOUBLE
    148  1.11  riastrad 
    149  1.11  riastrad /*
    150  1.11  riastrad  * Use one bit more than fits in IEEE 754 binary64.
    151  1.11  riastrad  */
    152  1.11  riastrad static const struct {
    153  1.11  riastrad 	int round_mode;
    154  1.11  riastrad 	long double input;
    155  1.13  riastrad 	intmax_t expected;
    156  1.11  riastrad } valuesl[] = {
    157  1.13  riastrad 	{ FE_TOWARDZERO,	0x2.00000000000008p+52L, 0x20000000000000 },
    158  1.13  riastrad 	{ FE_DOWNWARD,		0x2.00000000000008p+52L, 0x20000000000000 },
    159  1.13  riastrad 	{ FE_UPWARD,		0x2.00000000000008p+52L, 0x20000000000001 },
    160  1.13  riastrad 	{ FE_TONEAREST,		0x2.00000000000008p+52L, 0x20000000000000 },
    161  1.13  riastrad 	{ FE_TOWARDZERO,	0x2.00000000000018p+52L, 0x20000000000001 },
    162  1.13  riastrad 	{ FE_DOWNWARD,		0x2.00000000000018p+52L, 0x20000000000001 },
    163  1.13  riastrad 	{ FE_UPWARD,		0x2.00000000000018p+52L, 0x20000000000002 },
    164  1.13  riastrad 	{ FE_TONEAREST,		0x2.00000000000018p+52L, 0x20000000000002 },
    165  1.11  riastrad };
    166  1.11  riastrad 
    167  1.11  riastrad ATF_TC(fe_nearbyintl);
    168  1.11  riastrad ATF_TC_HEAD(fe_nearbyintl, tc)
    169  1.11  riastrad {
    170  1.11  riastrad 	atf_tc_set_md_var(tc, "descr",
    171  1.11  riastrad 	    "Checking IEEE 754 rounding modes using nearbyintl");
    172  1.11  riastrad }
    173  1.11  riastrad 
    174  1.11  riastrad ATF_TC_BODY(fe_nearbyintl, tc)
    175  1.11  riastrad {
    176  1.11  riastrad 	long double received, ipart, fpart;
    177  1.11  riastrad 
    178  1.11  riastrad 	for (unsigned int i = 0; i < __arraycount(valuesl); i++) {
    179  1.11  riastrad 		fesetround(valuesl[i].round_mode);
    180  1.11  riastrad 
    181  1.11  riastrad 		received = nearbyintl(valuesl[i].input);
    182  1.11  riastrad 		fpart = modfl(received, &ipart);
    183  1.11  riastrad 		ATF_CHECK_MSG(fpart == 0,
    184  1.11  riastrad 		    "%s nearbyintl(%Lf) has fractional part %Lf",
    185  1.11  riastrad 		    rmname(values[i].round_mode), valuesl[i].input, fpart);
    186  1.11  riastrad 		ATF_CHECK_MSG((long int)received == valuesl[i].expected,
    187  1.12       kre 		    "%s [%u] nearbyint(%Lf): got %Lf, expected %jd",
    188  1.11  riastrad 		    rmname(values[i].round_mode), i,
    189  1.11  riastrad 		    valuesl[i].input, received, valuesl[i].expected);
    190  1.11  riastrad 
    191  1.11  riastrad 		/* Do we get the same rounding mode out? */
    192  1.11  riastrad 		ATF_CHECK_MSG(fegetround() == valuesl[i].round_mode,
    193  1.11  riastrad 		    "[%u] set %d (%s), got %d (%s)",
    194  1.11  riastrad 		    i,
    195  1.11  riastrad 		    valuesl[i].round_mode, rmname(valuesl[i].round_mode),
    196  1.11  riastrad 		    fegetround(), rmname(fegetround()));
    197  1.11  riastrad 	}
    198  1.11  riastrad }
    199  1.11  riastrad 
    200  1.11  riastrad #endif
    201  1.11  riastrad 
    202   1.7        he static const struct {
    203   1.7        he 	double input;
    204   1.7        he 	double toward;
    205   1.7        he 	double expected;
    206   1.7        he } values2[] = {
    207   1.7        he 	{ 10.0, 11.0, 10.0 },
    208   1.7        he 	{ -5.0, -6.0, -5.0 },
    209   1.7        he };
    210   1.7        he 
    211   1.7        he ATF_TC(fe_nextafter);
    212   1.7        he ATF_TC_HEAD(fe_nextafter, tc)
    213   1.7        he {
    214   1.7        he 	atf_tc_set_md_var(tc, "descr", "Checking IEEE 754 rounding using nextafter()");
    215   1.7        he }
    216   1.7        he 
    217   1.7        he ATF_TC_BODY(fe_nextafter, tc)
    218   1.7        he {
    219   1.7        he 	double received;
    220   1.7        he 	int res;
    221   1.7        he 
    222   1.7        he 	for (unsigned int i = 0; i < __arraycount(values2); i++) {
    223   1.7        he 		received = nextafter(values2[i].input, values2[i].toward);
    224   1.7        he 		if (values2[i].input < values2[i].toward) {
    225   1.7        he 			res = (received > values2[i].input);
    226   1.7        he 		} else {
    227   1.7        he 			res = (received < values2[i].input);
    228   1.7        he 		}
    229   1.7        he 		ATF_CHECK_MSG(
    230   1.7        he 			res && (fabs(received - values2[i].expected) < EPSILON),
    231   1.7        he 			"nextafter() rounding wrong, difference too large\n"
    232   1.7        he 			"input: %f (index %d): got %f, expected %f, res %d\n",
    233   1.7        he 			values2[i].input, i, received, values2[i].expected, res);
    234   1.7        he 	}
    235   1.7        he }
    236   1.7        he 
    237   1.7        he ATF_TC(fe_nexttoward);
    238   1.7        he ATF_TC_HEAD(fe_nexttoward, tc)
    239   1.7        he {
    240   1.7        he 	atf_tc_set_md_var(tc, "descr", "Checking IEEE 754 rounding using nexttoward()");
    241   1.7        he }
    242   1.7        he 
    243   1.7        he ATF_TC_BODY(fe_nexttoward, tc)
    244   1.7        he {
    245   1.7        he 	double received;
    246   1.7        he 	int res;
    247   1.7        he 
    248   1.7        he 	for (unsigned int i = 0; i < __arraycount(values2); i++) {
    249   1.7        he 		received = nexttoward(values2[i].input, values2[i].toward);
    250   1.7        he 		if (values2[i].input < values2[i].toward) {
    251   1.7        he 			res = (received > values2[i].input);
    252   1.7        he 		} else {
    253   1.7        he 			res = (received < values2[i].input);
    254   1.7        he 		}
    255   1.7        he 		ATF_CHECK_MSG(
    256   1.7        he 			res && (fabs(received - values2[i].expected) < EPSILON),
    257   1.7        he 			"nexttoward() rounding wrong, difference too large\n"
    258   1.7        he 			"input: %f (index %d): got %f, expected %f, res %d\n",
    259   1.7        he 			values2[i].input, i, received, values2[i].expected, res);
    260   1.7        he 	}
    261   1.7        he }
    262   1.7        he 
    263   1.1      maya ATF_TP_ADD_TCS(tp)
    264   1.1      maya {
    265   1.1      maya 
    266   1.1      maya 	ATF_TP_ADD_TC(tp, fe_round);
    267   1.6        he 	ATF_TP_ADD_TC(tp, fe_nearbyint);
    268  1.11  riastrad #ifdef __HAVE_LONG_DOUBLE
    269  1.11  riastrad 	ATF_TP_ADD_TC(tp, fe_nearbyintl);
    270  1.11  riastrad #endif
    271   1.7        he 	ATF_TP_ADD_TC(tp, fe_nextafter);
    272   1.7        he 	ATF_TP_ADD_TC(tp, fe_nexttoward);
    273   1.1      maya 
    274   1.1      maya 	return atf_no_error();
    275   1.1      maya }
    276   1.1      maya #else
    277   1.1      maya ATF_TC(t_nofe_round);
    278   1.1      maya 
    279   1.1      maya ATF_TC_HEAD(t_nofe_round, tc)
    280   1.1      maya {
    281   1.1      maya 	atf_tc_set_md_var(tc, "descr",
    282   1.1      maya 	    "dummy test case - no fenv.h support");
    283   1.1      maya }
    284   1.1      maya 
    285   1.4        he ATF_TC_BODY(t_nofe_round, tc)
    286   1.4        he {
    287   1.4        he 	atf_tc_skip("no fenv.h support on this architecture");
    288   1.4        he }
    289   1.1      maya 
    290   1.6        he ATF_TC(t_nofe_nearbyint);
    291   1.6        he 
    292   1.6        he ATF_TC_HEAD(t_nofe_nearbyint, tc)
    293   1.6        he {
    294   1.6        he 	atf_tc_set_md_var(tc, "descr",
    295   1.6        he 	    "dummy test case - no fenv.h support");
    296   1.6        he }
    297   1.6        he 
    298   1.6        he ATF_TC_BODY(t_nofe_nearbyint, tc)
    299   1.6        he {
    300   1.6        he 	atf_tc_skip("no fenv.h support on this architecture");
    301   1.6        he }
    302   1.6        he 
    303   1.7        he ATF_TC(t_nofe_nextafter);
    304   1.7        he 
    305   1.7        he ATF_TC_HEAD(t_nofe_nextafter, tc)
    306   1.7        he {
    307   1.7        he 	atf_tc_set_md_var(tc, "descr",
    308   1.7        he 	    "dummy test case - no fenv.h support");
    309   1.7        he }
    310   1.7        he 
    311   1.7        he ATF_TC_BODY(t_nofe_nextafter, tc)
    312   1.7        he {
    313   1.7        he 	atf_tc_skip("no fenv.h support on this architecture");
    314   1.7        he }
    315   1.7        he 
    316   1.7        he ATF_TC(t_nofe_nexttoward);
    317   1.7        he 
    318   1.7        he ATF_TC_HEAD(t_nofe_nexttoward, tc)
    319   1.7        he {
    320   1.7        he 	atf_tc_set_md_var(tc, "descr",
    321   1.7        he 	    "dummy test case - no fenv.h support");
    322   1.7        he }
    323   1.7        he 
    324   1.7        he ATF_TC_BODY(t_nofe_nexttoward, tc)
    325   1.7        he {
    326   1.7        he 	atf_tc_skip("no fenv.h support on this architecture");
    327   1.7        he }
    328   1.6        he 
    329   1.1      maya ATF_TP_ADD_TCS(tp)
    330   1.1      maya {
    331   1.1      maya 	ATF_TP_ADD_TC(tp, t_nofe_round);
    332   1.6        he 	ATF_TP_ADD_TC(tp, t_nofe_nearbyint);
    333   1.7        he 	ATF_TP_ADD_TC(tp, t_nofe_nextafter);
    334   1.7        he 	ATF_TP_ADD_TC(tp, t_nofe_nexttoward);
    335   1.1      maya 	return atf_no_error();
    336   1.1      maya }
    337   1.1      maya 
    338   1.1      maya #endif
    339