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
66 // Intentionally not explicit. Conversion from double to Interval is common
67 // and reasonable.
Interval(double val)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
Interval(bool hasNaN_,double lo_,double hi_)73 Interval (bool hasNaN_, double lo_, double hi_)
74 : m_hasNaN(hasNaN_), m_lo(lo_), m_hi(hi_) {}
75
Interval(const Interval & a,const Interval & b)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
length(void) const81 double length (void) const { return m_hi - m_lo; }
lo(void) const82 double lo (void) const { return m_lo; }
hi(void) const83 double hi (void) const { return m_hi; }
hasNaN(void) const84 bool hasNaN (void) const { return m_hasNaN; }
nan(void) const85 Interval nan (void) const { return m_hasNaN ? TCU_NAN : Interval(); }
empty(void) const86 bool empty (void) const { return m_lo > m_hi; }
isFinite(void) const87 bool isFinite (void) const { return m_lo > -TCU_INFINITY && m_hi < TCU_INFINITY; }
isOrdinary(void) const88 bool isOrdinary (void) const { return !hasNaN() && !empty() && isFinite(); }
89
90
operator |(const Interval & other) const91 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
operator |=(const Interval & other)99 Interval& operator|= (const Interval& other)
100 {
101 return (*this = *this | other);
102 }
103
operator &(const Interval & other) const104 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
operator &=(const Interval & other)111 Interval& operator&= (const Interval& other)
112 {
113 return (*this = *this & other);
114 }
115
contains(const Interval & other) const116 bool contains (const Interval& other) const
117 {
118 return (other.lo() >= lo() && other.hi() <= hi() &&
119 (!other.hasNaN() || hasNaN()));
120 }
121
intersects(const Interval & other) const122 bool intersects (const Interval& other) const
123 {
124 return ((other.hi() >= lo() && other.lo() <= hi()) ||
125 (other.hasNaN() && hasNaN()));
126 }
127
operator -(void) const128 Interval operator- (void) const
129 {
130 return Interval(hasNaN(), -hi(), -lo());
131 }
132
unbounded(bool nan=false)133 static Interval unbounded (bool nan = false)
134 {
135 return Interval(nan, -TCU_INFINITY, TCU_INFINITY);
136 }
137
midpoint(void) const138 double midpoint (void) const
139 {
140 return 0.5 * (hi() + lo()); // returns NaN when not bounded
141 }
142
operator ==(const Interval & other) const143 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
operator +(const Interval & x)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
operator +=(Interval & x,const Interval & y)168 inline Interval& operator+= (Interval& x, const Interval& y) { return (x = x + y); }
operator -=(Interval & x,const Interval & y)169 inline Interval& operator-= (Interval& x, const Interval& y) { return (x = x - y); }
operator *=(Interval & x,const Interval & y)170 inline Interval& operator*= (Interval& x, const Interval& y) { return (x = x * y); }
operator /=(Interval & x,const Interval & 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