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:
ScopedRoundingMode(deRoundingMode mode)43 ScopedRoundingMode (deRoundingMode mode)
44 : m_oldMode (deGetRoundingMode()) { deSetRoundingMode(mode); }
45
ScopedRoundingMode(void)46 ScopedRoundingMode (void) : m_oldMode (deGetRoundingMode()) {}
47
~ScopedRoundingMode(void)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.
Interval(void)61 Interval (void)
62 : m_hasNaN (false)
63 , m_lo (TCU_INFINITY)
64 , m_hi (-TCU_INFINITY)
65 , m_warningLo (-TCU_INFINITY)
66 , m_warningHi (TCU_INFINITY) {}
67
68 // Intentionally not explicit. Conversion from double to Interval is common
69 // and reasonable.
Interval(double val)70 Interval (double val)
71 : m_hasNaN (!!deIsNaN(val))
72 , m_lo (m_hasNaN ? TCU_INFINITY : val)
73 , m_hi (m_hasNaN ? -TCU_INFINITY : val)
74 , m_warningLo (-TCU_INFINITY)
75 , m_warningHi (TCU_INFINITY) {}
76
77
Interval(bool hasNaN_,double lo_,double hi_)78 Interval(bool hasNaN_, double lo_, double hi_)
79 : m_hasNaN(hasNaN_), m_lo(lo_), m_hi(hi_), m_warningLo(-TCU_INFINITY), m_warningHi(TCU_INFINITY) {}
80
Interval(bool hasNaN_,double lo_,double hi_,double wlo_,double whi_)81 Interval(bool hasNaN_, double lo_, double hi_, double wlo_, double whi_)
82 : m_hasNaN(hasNaN_), m_lo(lo_), m_hi(hi_), m_warningLo(wlo_), m_warningHi(whi_) {}
83
Interval(const Interval & a,const Interval & b)84 Interval (const Interval& a, const Interval& b)
85 : m_hasNaN (a.m_hasNaN || b.m_hasNaN)
86 , m_lo (de::min(a.lo(), b.lo()))
87 , m_hi (de::max(a.hi(), b.hi()))
88 , m_warningLo (de::min(a.warningLo(), b.warningLo()))
89 , m_warningHi (de::max(a.warningHi(), b.warningHi())) {}
90
length(void) const91 double length (void) const { return m_hi - m_lo; }
lo(void) const92 double lo (void) const { return m_lo; }
hi(void) const93 double hi (void) const { return m_hi; }
warningLo(void) const94 double warningLo (void) const { return m_warningLo; }
warningHi(void) const95 double warningHi (void) const { return m_warningHi; }
hasNaN(void) const96 bool hasNaN (void) const { return m_hasNaN; }
nan(void) const97 Interval nan (void) const { return m_hasNaN ? TCU_NAN : Interval(); }
empty(void) const98 bool empty (void) const { return m_lo > m_hi; }
isFinite(void) const99 bool isFinite (void) const { return m_lo > -TCU_INFINITY && m_hi < TCU_INFINITY; }
isOrdinary(void) const100 bool isOrdinary (void) const { return !hasNaN() && !empty() && isFinite(); }
101
warning(double lo_,double hi_)102 void warning (double lo_, double hi_)
103 {
104 m_warningLo = lo_;
105 m_warningHi = hi_;
106 }
107
operator |(const Interval & other) const108 Interval operator| (const Interval& other) const
109 {
110 return Interval(m_hasNaN || other.m_hasNaN,
111 de::min(m_lo, other.m_lo),
112 de::max(m_hi, other.m_hi),
113 de::min(m_warningLo, other.m_warningLo),
114 de::max(m_warningHi, other.m_warningHi));
115 }
116
operator |=(const Interval & other)117 Interval& operator|= (const Interval& other)
118 {
119 return (*this = *this | other);
120 }
121
operator &(const Interval & other) const122 Interval operator& (const Interval& other) const
123 {
124 return Interval(m_hasNaN && other.m_hasNaN,
125 de::max(m_lo, other.m_lo),
126 de::min(m_hi, other.m_hi),
127 de::max(m_warningLo, other.m_warningLo),
128 de::min(m_warningHi, other.m_warningHi));
129 }
130
operator &=(const Interval & other)131 Interval& operator&= (const Interval& other)
132 {
133 return (*this = *this & other);
134 }
135
contains(const Interval & other) const136 bool contains (const Interval& other) const
137 {
138 return (other.lo() >= lo() && other.hi() <= hi() &&
139 (!other.hasNaN() || hasNaN()));
140 }
141
containsWarning(const Interval & other) const142 bool containsWarning(const Interval& other) const
143 {
144 return (other.lo() >= warningLo() && other.hi() <= warningHi() &&
145 (!other.hasNaN() || hasNaN()));
146 }
147
intersects(const Interval & other) const148 bool intersects (const Interval& other) const
149 {
150 return ((other.hi() >= lo() && other.lo() <= hi()) ||
151 (other.hasNaN() && hasNaN()));
152 }
153
operator -(void) const154 Interval operator- (void) const
155 {
156 return Interval(hasNaN(), -hi(), -lo(), -warningHi(), -warningLo());
157 }
158
unbounded(bool nan=false)159 static Interval unbounded (bool nan = false)
160 {
161 return Interval(nan, -TCU_INFINITY, TCU_INFINITY);
162 }
163
midpoint(void) const164 double midpoint (void) const
165 {
166 return 0.5 * (hi() + lo()); // returns NaN when not bounded
167 }
168
operator ==(const Interval & other) const169 bool operator== (const Interval& other) const
170 {
171 return ((m_hasNaN == other.m_hasNaN) &&
172 ((empty() && other.empty()) ||
173 (m_lo == other.m_lo && m_hi == other.m_hi)));
174 }
175
176 private:
177 bool m_hasNaN;
178 double m_lo;
179 double m_hi;
180 double m_warningLo;
181 double m_warningHi;
182 } DE_WARN_UNUSED_TYPE;
183
operator +(const Interval & x)184 inline Interval operator+ (const Interval& x) { return x; }
185 Interval exp2 (const Interval& x);
186 Interval exp (const Interval& x);
187 int sign (const Interval& x);
188 Interval abs (const Interval& x);
189 Interval inverseSqrt (const Interval& x);
190
191 Interval operator+ (const Interval& x, const Interval& y);
192 Interval operator- (const Interval& x, const Interval& y);
193 Interval operator* (const Interval& x, const Interval& y);
194 Interval operator/ (const Interval& nom, const Interval& den);
195
operator +=(Interval & x,const Interval & y)196 inline Interval& operator+= (Interval& x, const Interval& y) { return (x = x + y); }
operator -=(Interval & x,const Interval & y)197 inline Interval& operator-= (Interval& x, const Interval& y) { return (x = x - y); }
operator *=(Interval & x,const Interval & y)198 inline Interval& operator*= (Interval& x, const Interval& y) { return (x = x * y); }
operator /=(Interval & x,const Interval & y)199 inline Interval& operator/= (Interval& x, const Interval& y) { return (x = x / y); }
200
201 std::ostream& operator<< (std::ostream& os, const Interval& interval);
202
203 #define TCU_SET_INTERVAL_BOUNDS(DST, VAR, SETLOW, SETHIGH) do \
204 { \
205 ::tcu::ScopedRoundingMode VAR##_ctx_; \
206 ::tcu::Interval& VAR##_dst_ = (DST); \
207 ::tcu::Interval VAR##_lo_; \
208 ::tcu::Interval VAR##_hi_; \
209 \
210 { \
211 ::tcu::Interval& VAR = VAR##_lo_; \
212 ::deSetRoundingMode(DE_ROUNDINGMODE_TO_NEGATIVE_INF); \
213 SETLOW; \
214 } \
215 { \
216 ::tcu::Interval& VAR = VAR##_hi_; \
217 ::deSetRoundingMode(DE_ROUNDINGMODE_TO_POSITIVE_INF); \
218 SETHIGH; \
219 } \
220 \
221 VAR##_dst_ = VAR##_lo_ | VAR##_hi_; \
222 } while (::deGetFalse())
223
224 #define TCU_SET_INTERVAL(DST, VAR, BODY) \
225 TCU_SET_INTERVAL_BOUNDS(DST, VAR, BODY, BODY)
226
227 //! Set the interval DST to the image of BODY on ARG, assuming that BODY on
228 //! ARG is a monotone function. In practice, BODY is evaluated on both the
229 //! upper and lower bound of ARG, and DST is set to the union of these
230 //! results. While evaluating BODY, PARAM is bound to the bound of ARG, and
231 //! the output of BODY should be stored in VAR.
232 #define TCU_INTERVAL_APPLY_MONOTONE1(DST, PARAM, ARG, VAR, BODY) do \
233 { \
234 const ::tcu::Interval& VAR##_arg_ = (ARG); \
235 ::tcu::Interval& VAR##_dst_ = (DST); \
236 ::tcu::Interval VAR##_lo_; \
237 ::tcu::Interval VAR##_hi_; \
238 if (VAR##_arg_.empty()) \
239 VAR##_dst_ = Interval(); \
240 else \
241 { \
242 { \
243 const double PARAM = VAR##_arg_.lo(); \
244 ::tcu::Interval& VAR = VAR##_lo_; \
245 BODY; \
246 } \
247 { \
248 const double PARAM = VAR##_arg_.hi(); \
249 ::tcu::Interval& VAR = VAR##_hi_; \
250 BODY; \
251 } \
252 VAR##_dst_ = VAR##_lo_ | VAR##_hi_; \
253 } \
254 if (VAR##_arg_.hasNaN()) \
255 VAR##_dst_ |= TCU_NAN; \
256 } while (::deGetFalse())
257
258 #define TCU_INTERVAL_APPLY_MONOTONE2(DST, P0, A0, P1, A1, VAR, BODY) \
259 TCU_INTERVAL_APPLY_MONOTONE1( \
260 DST, P0, A0, tmp2_, \
261 TCU_INTERVAL_APPLY_MONOTONE1(tmp2_, P1, A1, VAR, BODY))
262
263 #define TCU_INTERVAL_APPLY_MONOTONE3(DST, P0, A0, P1, A1, P2, A2, VAR, BODY) \
264 TCU_INTERVAL_APPLY_MONOTONE1( \
265 DST, P0, A0, tmp3_, \
266 TCU_INTERVAL_APPLY_MONOTONE2(tmp3_, P1, A1, P2, A2, VAR, BODY))
267
268 typedef double DoubleFunc1 (double);
269 typedef double DoubleFunc2 (double, double);
270 typedef double DoubleFunc3 (double, double, double);
271 typedef Interval DoubleIntervalFunc1 (double);
272 typedef Interval DoubleIntervalFunc2 (double, double);
273 typedef Interval DoubleIntervalFunc3 (double, double, double);
274
275 Interval applyMonotone (DoubleFunc1& func,
276 const Interval& arg0);
277 Interval applyMonotone (DoubleFunc2& func,
278 const Interval& arg0,
279 const Interval& arg1);
280 Interval applyMonotone (DoubleIntervalFunc1& func,
281 const Interval& arg0);
282 Interval applyMonotone (DoubleIntervalFunc2& func,
283 const Interval& arg0,
284 const Interval& arg1);
285
286
287 } // tcu
288
289 #endif // _TCUINTERVAL_HPP
290