Home | History | Annotate | Download | only in common
      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 
     36 namespace tcu
     37 {
     38 
     39 // RAII context for temporarily changing the rounding mode
     40 class ScopedRoundingMode
     41 {
     42 public:
     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 
     50 private:
     51 							ScopedRoundingMode	(const ScopedRoundingMode&);
     52 	ScopedRoundingMode&		operator=			(const ScopedRoundingMode&);
     53 
     54 	const deRoundingMode	m_oldMode;
     55 };
     56 
     57 class Interval
     58 {
     59 public:
     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 
    150 private:
    151 	bool		m_hasNaN;
    152 	double		m_lo;
    153 	double		m_hi;
    154 } DE_WARN_UNUSED_TYPE;
    155 
    156 inline Interval	operator+	(const Interval& x) { return x; }
    157 Interval		exp2		(const Interval& x);
    158 Interval		exp			(const Interval& x);
    159 int				sign		(const Interval& x);
    160 Interval		abs			(const Interval& x);
    161 Interval		inverseSqrt	(const Interval& x);
    162 
    163 Interval		operator+	(const Interval& x,		const Interval& y);
    164 Interval		operator-	(const Interval& x,		const Interval& y);
    165 Interval		operator*	(const Interval& x,		const Interval& y);
    166 Interval		operator/	(const Interval& nom,	const Interval& den);
    167 
    168 inline Interval& operator+=	(Interval& x,	const Interval& y) { return (x = x + y); }
    169 inline Interval& operator-=	(Interval& x,	const Interval& y) { return (x = x - y); }
    170 inline Interval& operator*=	(Interval& x,	const Interval& y) { return (x = x * y); }
    171 inline Interval& operator/=	(Interval& x,	const Interval& y) { return (x = x / y); }
    172 
    173 std::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 
    240 typedef double		DoubleFunc1			(double);
    241 typedef double		DoubleFunc2			(double, double);
    242 typedef double		DoubleFunc3			(double, double, double);
    243 typedef Interval	DoubleIntervalFunc1	(double);
    244 typedef Interval	DoubleIntervalFunc2	(double, double);
    245 typedef Interval	DoubleIntervalFunc3	(double, double, double);
    246 
    247 Interval	applyMonotone	(DoubleFunc1&			func,
    248 							 const Interval&		arg0);
    249 Interval	applyMonotone	(DoubleFunc2&			func,
    250 							 const Interval&		arg0,
    251 							 const Interval&		arg1);
    252 Interval	applyMonotone	(DoubleIntervalFunc1&	func,
    253 							 const Interval&		arg0);
    254 Interval	applyMonotone	(DoubleIntervalFunc2&	func,
    255 							 const Interval&		arg0,
    256 							 const Interval&		arg1);
    257 
    258 
    259 } // tcu
    260 
    261 #endif // _TCUINTERVAL_HPP
    262