1311970Sngie/*
2311970Sngie * Written by Maya Rashish <maya@NetBSD.org>
3311970Sngie * Public domain.
4311970Sngie *
5311970Sngie * Testing IEEE-754 rounding modes (and lrint)
6311970Sngie */
7311970Sngie
8311970Sngie#include <atf-c.h>
9311970Sngie#include <fenv.h>
10311970Sngie#ifdef __HAVE_FENV
11311970Sngie#include <math.h>
12311970Sngie#include <stdio.h>
13311970Sngie#include <stdlib.h>
14311970Sngie
15311970Sngie/*#pragma STDC FENV_ACCESS ON gcc?? */
16311970Sngie
17311970Sngie#define INT 9223L
18311970Sngie
19311970Sngie#define EPSILON 0.001
20311970Sngie
21311970Sngiestatic const struct {
22311970Sngie	int round_mode;
23311970Sngie	double input;
24311970Sngie	long int expected;
25311970Sngie} values[] = {
26311970Sngie	{ FE_DOWNWARD,		3.7,		3},
27311970Sngie	{ FE_DOWNWARD,		-3.7,		-4},
28311970Sngie	{ FE_DOWNWARD,		+0,		0},
29311970Sngie	{ FE_DOWNWARD,		-INT-0.01,	-INT-1},
30311970Sngie	{ FE_DOWNWARD,		+INT-0.01,	INT-1},
31311970Sngie	{ FE_DOWNWARD,		-INT+0.01,	-INT},
32311970Sngie	{ FE_DOWNWARD,		+INT+0.01,	INT},
33311970Sngie#if 0 /* cpu bugs? */
34311970Sngie	{ FE_DOWNWARD,		-0,		-1},
35311970Sngie
36311970Sngie	{ FE_UPWARD,		+0,		1},
37311970Sngie#endif
38311970Sngie	{ FE_UPWARD,		-0,		0},
39311970Sngie	{ FE_UPWARD,		-123.7,		-123},
40311970Sngie	{ FE_UPWARD,		123.999,	124},
41311970Sngie	{ FE_UPWARD,		-INT-0.01,	-INT},
42311970Sngie	{ FE_UPWARD,		+INT-0.01,	INT},
43311970Sngie	{ FE_UPWARD,		-INT+0.01,	-INT+1},
44311970Sngie	{ FE_UPWARD,		+INT+0.01,	INT+1},
45311970Sngie
46311970Sngie	{ FE_TOWARDZERO,	1.99,		1},
47311970Sngie	{ FE_TOWARDZERO,	-1.99,		-1},
48311970Sngie	{ FE_TOWARDZERO,	0.2,		0},
49311970Sngie	{ FE_TOWARDZERO,	INT+0.01,	INT},
50311970Sngie	{ FE_TOWARDZERO,	INT-0.01,	INT - 1},
51311970Sngie	{ FE_TOWARDZERO,	-INT+0.01,	-INT + 1},
52311970Sngie	{ FE_TOWARDZERO,	+0,		0},
53311970Sngie	{ FE_TOWARDZERO,	-0,		0},
54311970Sngie
55311970Sngie	{ FE_TONEAREST,		-INT-0.01,	-INT},
56311970Sngie	{ FE_TONEAREST,		+INT-0.01,	INT},
57311970Sngie	{ FE_TONEAREST,		-INT+0.01,	-INT},
58311970Sngie	{ FE_TONEAREST,		+INT+0.01,	INT},
59311970Sngie	{ FE_TONEAREST,		-INT-0.501,	-INT-1},
60311970Sngie	{ FE_TONEAREST,		+INT-0.501,	INT-1},
61311970Sngie	{ FE_TONEAREST,		-INT+0.501,	-INT+1},
62311970Sngie	{ FE_TONEAREST,		+INT+0.501,	INT+1},
63311970Sngie	{ FE_TONEAREST,		+0,		0},
64311970Sngie	{ FE_TONEAREST,		-0,		0},
65311970Sngie};
66311970Sngie
67311970SngieATF_TC(fe_round);
68311970SngieATF_TC_HEAD(fe_round, tc)
69311970Sngie{
70311970Sngie	atf_tc_set_md_var(tc, "descr","Checking IEEE 754 rounding modes using lrint");
71311970Sngie}
72311970Sngie
73311970SngieATF_TC_BODY(fe_round, tc)
74311970Sngie{
75311970Sngie	long int received;
76311970Sngie
77311970Sngie	for (unsigned int i = 0; i < __arraycount(values); i++) {
78311970Sngie		fesetround(values[i].round_mode);
79311970Sngie
80311970Sngie		received = lrint(values[i].input);
81311970Sngie		ATF_CHECK_MSG(
82311970Sngie		    (labs(received - values[i].expected) < EPSILON),
83311970Sngie		    "lrint rounding wrong, difference too large\n"
84311970Sngie		    "input: %f (index %d): got %ld, expected %ld\n",
85311970Sngie		    values[i].input, i, received, values[i].expected);
86311970Sngie
87311970Sngie		/* Do we get the same rounding mode out? */
88311970Sngie		ATF_CHECK_MSG(
89311970Sngie		    (fegetround() == values[i].round_mode),
90311970Sngie		    "Didn't get the same rounding mode out!\n"
91311970Sngie		    "(index %d) fed in %d rounding mode, got %d out\n",
92311970Sngie		    i, fegetround(), values[i].round_mode);
93311970Sngie	}
94311970Sngie}
95311970Sngie
96311970SngieATF_TP_ADD_TCS(tp)
97311970Sngie{
98311970Sngie
99311970Sngie	ATF_TP_ADD_TC(tp, fe_round);
100311970Sngie
101311970Sngie	return atf_no_error();
102311970Sngie}
103311970Sngie#else
104311970SngieATF_TC(t_nofe_round);
105311970Sngie
106311970SngieATF_TC_HEAD(t_nofe_round, tc)
107311970Sngie{
108311970Sngie	atf_tc_set_md_var(tc, "descr",
109311970Sngie	    "dummy test case - no fenv.h support");
110311970Sngie}
111311970Sngie
112311970Sngie
113311970SngieATF_TC_BODY(t_nofe_round, tc)
114311970Sngie{
115311970Sngie	atf_tc_skip("no fenv.h support on this architecture");
116311970Sngie}
117311970Sngie
118311970SngieATF_TP_ADD_TCS(tp)
119311970Sngie{
120311970Sngie	ATF_TP_ADD_TC(tp, t_nofe_round);
121311970Sngie	return atf_no_error();
122311970Sngie}
123311970Sngie
124311970Sngie#endif
125