Home | History | Annotate | Line # | Download | only in libm
t_fe_round.c revision 1.1
      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 		    (abs(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, fegetround(), values[i].round_mode);
     93 	}
     94 }
     95 
     96 ATF_TP_ADD_TCS(tp)
     97 {
     98 
     99 	ATF_TP_ADD_TC(tp, fe_round);
    100 
    101 	return atf_no_error();
    102 }
    103 #else
    104 ATF_TC(t_nofe_round);
    105 
    106 ATF_TC_HEAD(t_nofe_round, tc)
    107 {
    108 	atf_tc_set_md_var(tc, "descr",
    109 	    "dummy test case - no fenv.h support");
    110 }
    111 
    112 
    113 ATF_TC_BODY(t_nofe_round, tc)
    114 {
    115 	atf_tc_skip("no fenv.h support on this architecture");
    116 }
    117 
    118 ATF_TP_ADD_TCS(tp)
    119 {
    120 	ATF_TP_ADD_TC(tp, t_nofe_round);
    121 	return atf_no_error();
    122 }
    123 
    124 #endif
    125