1#ifndef _TCUINTERVAL_HPP
2#define _TCUINTERVAL_HPP
3/*-------------------------------------------------------------------------
4 * drawElements Quality Program Tester Core
5 * ----------------------------------------
6 *
7 * Copyright 2014 The Android Open Source Project
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 *
21 *//*!
22 * \file
23 * \brief Interval arithmetic and floating point precisions.
24 *//*--------------------------------------------------------------------*/
25
26#include "tcuDefs.hpp"
27
28#include "deMath.h"
29
30#include <iostream>
31#include <limits>
32
33#define TCU_INFINITY	(::std::numeric_limits<float>::infinity())
34#define TCU_NAN			(::std::numeric_limits<float>::quiet_NaN())
35
36namespace tcu
37{
38
39// RAII context for temporarily changing the rounding mode
40class ScopedRoundingMode
41{
42public:
43							ScopedRoundingMode	(deRoundingMode mode)
44								: m_oldMode (deGetRoundingMode()) { deSetRoundingMode(mode); }
45
46							ScopedRoundingMode	(void) : m_oldMode (deGetRoundingMode()) {}
47
48							~ScopedRoundingMode	(void)	{ deSetRoundingMode(m_oldMode); }
49
50private:
51							ScopedRoundingMode	(const ScopedRoundingMode&);
52	ScopedRoundingMode&		operator=			(const ScopedRoundingMode&);
53
54	const deRoundingMode	m_oldMode;
55};
56
57class Interval
58{
59public:
60				// Empty interval.
61				Interval		(void)
62					: m_hasNaN	(false)
63					, m_lo		(TCU_INFINITY)
64					, m_hi		(-TCU_INFINITY) {}
65
66				// Intentionally not explicit. Conversion from double to Interval is common
67				// and reasonable.
68				Interval		(double val)
69					: m_hasNaN	(!!deIsNaN(val))
70					, m_lo		(m_hasNaN ? TCU_INFINITY : val)
71					, m_hi		(m_hasNaN ? -TCU_INFINITY : val) {}
72
73				Interval		(bool hasNaN_, double lo_, double hi_)
74					: m_hasNaN(hasNaN_), m_lo(lo_), m_hi(hi_) {}
75
76				Interval		(const Interval& a, const Interval& b)
77					: m_hasNaN	(a.m_hasNaN || b.m_hasNaN)
78					, m_lo		(de::min(a.lo(), b.lo()))
79					, m_hi		(de::max(a.hi(), b.hi())) {}
80
81	double		length			(void) const { return m_hi - m_lo; }
82	double		lo				(void) const { return m_lo; }
83	double		hi				(void) const { return m_hi; }
84	bool		hasNaN			(void) const { return m_hasNaN; }
85	Interval	nan				(void) const { return m_hasNaN ? TCU_NAN : Interval(); }
86	bool		empty			(void) const { return m_lo > m_hi; }
87	bool		isFinite		(void) const { return m_lo > -TCU_INFINITY && m_hi < TCU_INFINITY; }
88	bool		isOrdinary		(void) const { return !hasNaN() && !empty() && isFinite(); }
89
90
91	Interval	operator|		(const Interval& other) const
92	{
93		return Interval(m_hasNaN || other.m_hasNaN,
94						de::min(m_lo, other.m_lo),
95						de::max(m_hi, other.m_hi));
96
97	}
98
99	Interval&	operator|=		(const Interval& other)
100	{
101		return (*this = *this | other);
102	}
103
104	Interval	operator&		(const Interval& other) const
105	{
106		return Interval(m_hasNaN && other.m_hasNaN,
107						de::max(m_lo, other.m_lo),
108						de::min(m_hi, other.m_hi));
109	}
110
111	Interval&	operator&=		(const Interval& other)
112	{
113		return (*this = *this & other);
114	}
115
116	bool		contains		(const Interval& other) const
117	{
118		return (other.lo() >= lo() && other.hi() <= hi() &&
119				(!other.hasNaN() || hasNaN()));
120	}
121
122	bool		intersects		(const Interval& other) const
123	{
124		return ((other.hi() >= lo() && other.lo() <= hi()) ||
125				(other.hasNaN() && hasNaN()));
126	}
127
128	Interval	operator-		(void) const
129	{
130		return Interval(hasNaN(), -hi(), -lo());
131	}
132
133	static Interval	unbounded	(bool nan = false)
134	{
135		return Interval(nan, -TCU_INFINITY, TCU_INFINITY);
136	}
137
138	double		midpoint		(void) const
139	{
140		return 0.5 * (hi() + lo()); // returns NaN when not bounded
141	}
142
143	bool		operator==		(const Interval& other) const
144	{
145		return ((m_hasNaN == other.m_hasNaN) &&
146				((empty() && other.empty()) ||
147				 (m_lo == other.m_lo && m_hi == other.m_hi)));
148	}
149
150private:
151	bool		m_hasNaN;
152	double		m_lo;
153	double		m_hi;
154} DE_WARN_UNUSED_TYPE;
155
156inline Interval	operator+	(const Interval& x) { return x; }
157Interval		exp2		(const Interval& x);
158Interval		exp			(const Interval& x);
159int				sign		(const Interval& x);
160Interval		abs			(const Interval& x);
161Interval		inverseSqrt	(const Interval& x);
162
163Interval		operator+	(const Interval& x,		const Interval& y);
164Interval		operator-	(const Interval& x,		const Interval& y);
165Interval		operator*	(const Interval& x,		const Interval& y);
166Interval		operator/	(const Interval& nom,	const Interval& den);
167
168inline Interval& operator+=	(Interval& x,	const Interval& y) { return (x = x + y); }
169inline Interval& operator-=	(Interval& x,	const Interval& y) { return (x = x - y); }
170inline Interval& operator*=	(Interval& x,	const Interval& y) { return (x = x * y); }
171inline Interval& operator/=	(Interval& x,	const Interval& y) { return (x = x / y); }
172
173std::ostream&	operator<<	(std::ostream& os, const Interval& interval);
174
175#define TCU_SET_INTERVAL_BOUNDS(DST, VAR, SETLOW, SETHIGH) do	\
176{																\
177	::tcu::ScopedRoundingMode	VAR##_ctx_;						\
178	::tcu::Interval&			VAR##_dst_	= (DST);			\
179	::tcu::Interval				VAR##_lo_;						\
180	::tcu::Interval				VAR##_hi_;						\
181																\
182	{															\
183		::tcu::Interval&	(VAR) = VAR##_lo_;					\
184		::deSetRoundingMode(DE_ROUNDINGMODE_TO_NEGATIVE_INF);	\
185		SETLOW;													\
186	}															\
187	{															\
188		::tcu::Interval&	(VAR) = VAR##_hi_;					\
189		::deSetRoundingMode(DE_ROUNDINGMODE_TO_POSITIVE_INF);	\
190		SETHIGH;												\
191	}															\
192																\
193	VAR##_dst_ = VAR##_lo_ | VAR##_hi_;							\
194} while (::deGetFalse())
195
196#define TCU_SET_INTERVAL(DST, VAR, BODY)						\
197	TCU_SET_INTERVAL_BOUNDS(DST, VAR, BODY, BODY)
198
199//! Set the interval DST to the image of BODY on ARG, assuming that BODY on
200//! ARG is a monotone function. In practice, BODY is evaluated on both the
201//! upper and lower bound of ARG, and DST is set to the union of these
202//! results. While evaluating BODY, PARAM is bound to the bound of ARG, and
203//! the output of BODY should be stored in VAR.
204#define TCU_INTERVAL_APPLY_MONOTONE1(DST, PARAM, ARG, VAR, BODY) do		\
205	{																	\
206	const ::tcu::Interval&	VAR##_arg_		= (ARG);					\
207	::tcu::Interval&		VAR##_dst_		= (DST);					\
208	::tcu::Interval			VAR##_lo_;									\
209	::tcu::Interval			VAR##_hi_;									\
210	if (VAR##_arg_.empty())												\
211		VAR##_dst_ = Interval();										\
212	else																\
213	{																	\
214		{																\
215			const double		(PARAM)	= VAR##_arg_.lo();				\
216			::tcu::Interval&	(VAR)	= VAR##_lo_;					\
217			BODY;														\
218		}																\
219		{																\
220			const double		(PARAM)	= VAR##_arg_.hi();				\
221			::tcu::Interval&	(VAR)	= VAR##_hi_;					\
222			BODY;														\
223		}																\
224		VAR##_dst_ = VAR##_lo_ | VAR##_hi_;								\
225	}																	\
226	if (VAR##_arg_.hasNaN())											\
227		VAR##_dst_ |= TCU_NAN;											\
228} while (::deGetFalse())
229
230#define TCU_INTERVAL_APPLY_MONOTONE2(DST, P0, A0, P1, A1, VAR, BODY)	\
231	TCU_INTERVAL_APPLY_MONOTONE1(										\
232		DST, P0, A0, tmp2_,												\
233		TCU_INTERVAL_APPLY_MONOTONE1(tmp2_, P1, A1, VAR, BODY))
234
235#define TCU_INTERVAL_APPLY_MONOTONE3(DST, P0, A0, P1, A1, P2, A2, VAR, BODY) \
236	TCU_INTERVAL_APPLY_MONOTONE1(										\
237		DST, P0, A0, tmp3_,												\
238		TCU_INTERVAL_APPLY_MONOTONE2(tmp3_, P1, A1, P2, A2, VAR, BODY))
239
240typedef double		DoubleFunc1			(double);
241typedef double		DoubleFunc2			(double, double);
242typedef double		DoubleFunc3			(double, double, double);
243typedef Interval	DoubleIntervalFunc1	(double);
244typedef Interval	DoubleIntervalFunc2	(double, double);
245typedef Interval	DoubleIntervalFunc3	(double, double, double);
246
247Interval	applyMonotone	(DoubleFunc1&			func,
248							 const Interval&		arg0);
249Interval	applyMonotone	(DoubleFunc2&			func,
250							 const Interval&		arg0,
251							 const Interval&		arg1);
252Interval	applyMonotone	(DoubleIntervalFunc1&	func,
253							 const Interval&		arg0);
254Interval	applyMonotone	(DoubleIntervalFunc2&	func,
255							 const Interval&		arg0,
256							 const Interval&		arg1);
257
258
259} // tcu
260
261#endif // _TCUINTERVAL_HPP
262