Fix missing dependency on sparse binds
[platform/upstream/VK-GL-CTS.git] / framework / common / tcuInterval.hpp
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 #include <cmath>
33
34 #define TCU_INFINITY    (::std::numeric_limits<float>::infinity())
35 #define TCU_NAN                 (::std::numeric_limits<float>::quiet_NaN())
36
37 namespace tcu
38 {
39
40 // RAII context for temporarily changing the rounding mode
41 class ScopedRoundingMode
42 {
43 public:
44                                                         ScopedRoundingMode      (deRoundingMode mode)
45                                                                 : m_oldMode (deGetRoundingMode()) { deSetRoundingMode(mode); }
46
47                                                         ScopedRoundingMode      (void) : m_oldMode (deGetRoundingMode()) {}
48
49                                                         ~ScopedRoundingMode     (void)  { deSetRoundingMode(m_oldMode); }
50
51 private:
52                                                         ScopedRoundingMode      (const ScopedRoundingMode&);
53         ScopedRoundingMode&             operator=                       (const ScopedRoundingMode&);
54
55         const deRoundingMode    m_oldMode;
56 };
57
58 class Interval
59 {
60 public:
61                                 // Empty interval.
62                                 Interval                        (void)
63                                         : m_hasNaN              (false)
64                                         , m_lo                  (TCU_INFINITY)
65                                         , m_hi                  (-TCU_INFINITY)
66                                         , m_warningLo   (-TCU_INFINITY)
67                                         , m_warningHi   (TCU_INFINITY) {}
68
69                                 // Intentionally not explicit. Conversion from double to Interval is common
70                                 // and reasonable.
71                                 Interval                        (double val)
72                                         : m_hasNaN              (!!deIsNaN(val))
73                                         , m_lo                  (m_hasNaN ? TCU_INFINITY : val)
74                                         , m_hi                  (m_hasNaN ? -TCU_INFINITY : val)
75                                         , m_warningLo   (-TCU_INFINITY)
76                                         , m_warningHi   (TCU_INFINITY) {}
77
78
79                                 Interval(bool hasNaN_, double lo_, double hi_)
80                                         : m_hasNaN(hasNaN_), m_lo(lo_), m_hi(hi_), m_warningLo(-TCU_INFINITY), m_warningHi(TCU_INFINITY) {}
81
82                                 Interval(bool hasNaN_, double lo_, double hi_, double wlo_, double whi_)
83                                         : m_hasNaN(hasNaN_), m_lo(lo_), m_hi(hi_), m_warningLo(wlo_), m_warningHi(whi_) {}
84
85                                 Interval                (const Interval& a, const Interval& b)
86                                         : m_hasNaN              (a.m_hasNaN || b.m_hasNaN)
87                                         , m_lo                  (de::min(a.lo(), b.lo()))
88                                         , m_hi                  (de::max(a.hi(), b.hi()))
89                                         , m_warningLo   (de::min(a.warningLo(), b.warningLo()))
90                                         , m_warningHi   (de::max(a.warningHi(), b.warningHi())) {}
91
92         double          length                  (void) const { return m_hi - m_lo; }
93         double          lo                              (void) const { return m_lo; }
94         double          hi                              (void) const { return m_hi; }
95         double          warningLo               (void) const { return m_warningLo; }
96         double          warningHi               (void) const { return m_warningHi; }
97         bool            hasNaN                  (void) const { return m_hasNaN; }
98         Interval        nan                             (void) const { return m_hasNaN ? TCU_NAN : Interval(); }
99         bool            empty                   (void) const { return m_lo > m_hi; }
100
101         // The interval is represented in double, it can extend outside the range of smaller floating-point formats
102         // and get rounded to infinity.
103         bool            isFinite                (double maxValue) const { return m_lo > -maxValue && m_hi < maxValue; }
104         bool            isOrdinary              (double maxValue) const { return !hasNaN() && !empty() && isFinite(maxValue); }
105
106         void            warning                 (double lo_, double hi_)
107         {
108                 m_warningLo = lo_;
109                 m_warningHi = hi_;
110         }
111
112         Interval        operator|               (const Interval& other) const
113         {
114                 return Interval(m_hasNaN || other.m_hasNaN,
115                                                 de::min(m_lo, other.m_lo),
116                                                 de::max(m_hi, other.m_hi),
117                                                 de::min(m_warningLo, other.m_warningLo),
118                                                 de::max(m_warningHi, other.m_warningHi));
119         }
120
121         Interval&       operator|=              (const Interval& other)
122         {
123                 return (*this = *this | other);
124         }
125
126         Interval        operator&               (const Interval& other) const
127         {
128                 return Interval(m_hasNaN && other.m_hasNaN,
129                                                 de::max(m_lo, other.m_lo),
130                                                 de::min(m_hi, other.m_hi),
131                                                 de::max(m_warningLo, other.m_warningLo),
132                                                 de::min(m_warningHi, other.m_warningHi));
133         }
134
135         Interval&       operator&=              (const Interval& other)
136         {
137                 return (*this = *this & other);
138         }
139
140         bool            contains                (const Interval& other) const
141         {
142                 return (other.lo() >= lo() && other.hi() <= hi() &&
143                                 (!other.hasNaN() || hasNaN()));
144         }
145
146         bool            containsWarning(const Interval& other) const
147         {
148                 return (other.lo() >= warningLo() && other.hi() <= warningHi() &&
149                         (!other.hasNaN() || hasNaN()));
150         }
151
152         bool            intersects              (const Interval& other) const
153         {
154                 return ((other.hi() >= lo() && other.lo() <= hi()) ||
155                                 (other.hasNaN() && hasNaN()));
156         }
157
158         Interval        operator-               (void) const
159         {
160                 return Interval(hasNaN(), -hi(), -lo(), -warningHi(), -warningLo());
161         }
162
163         static Interval unbounded       (bool nan = false)
164         {
165                 return Interval(nan, -TCU_INFINITY, TCU_INFINITY);
166         }
167
168         double          midpoint                (void) const
169         {
170                 const double    h = hi();
171                 const double    l = lo();
172
173                 if (h == -l)
174                         return 0.0;
175                 if (l == -TCU_INFINITY)
176                         return -TCU_INFINITY;
177                 if (h == TCU_INFINITY)
178                         return TCU_INFINITY;
179
180                 const bool              negativeH = ::std::signbit(h);
181                 const bool              negativeL = ::std::signbit(l);
182                 double                  ret;
183
184                 if (negativeH != negativeL)
185                 {
186                         // Different signs. Adding both values should be safe.
187                         ret = (h + l) * 0.5;
188                 }
189                 else
190                 {
191                         // Same sign. Substracting low from high should be safe.
192                         ret = l + (h - l) * 0.5;
193                 }
194
195                 return ret;
196         }
197
198         bool            operator==              (const Interval& other) const
199         {
200                 return ((m_hasNaN == other.m_hasNaN) &&
201                                 ((empty() && other.empty()) ||
202                                  (m_lo == other.m_lo && m_hi == other.m_hi)));
203         }
204
205 private:
206         bool            m_hasNaN;
207         double          m_lo;
208         double          m_hi;
209         double          m_warningLo;
210         double          m_warningHi;
211 } DE_WARN_UNUSED_TYPE;
212
213 inline Interval operator+       (const Interval& x) { return x; }
214 Interval                exp2            (const Interval& x);
215 Interval                exp                     (const Interval& x);
216 int                             sign            (const Interval& x);
217 Interval                abs                     (const Interval& x);
218 Interval                inverseSqrt     (const Interval& x);
219
220 Interval                operator+       (const Interval& x,             const Interval& y);
221 Interval                operator-       (const Interval& x,             const Interval& y);
222 Interval                operator*       (const Interval& x,             const Interval& y);
223 Interval                operator/       (const Interval& nom,   const Interval& den);
224
225 inline Interval& operator+=     (Interval& x,   const Interval& y) { return (x = x + y); }
226 inline Interval& operator-=     (Interval& x,   const Interval& y) { return (x = x - y); }
227 inline Interval& operator*=     (Interval& x,   const Interval& y) { return (x = x * y); }
228 inline Interval& operator/=     (Interval& x,   const Interval& y) { return (x = x / y); }
229
230 std::ostream&   operator<<      (std::ostream& os, const Interval& interval);
231
232 #define TCU_SET_INTERVAL_BOUNDS(DST, VAR, SETLOW, SETHIGH) do   \
233 {                                                                                                                               \
234         ::tcu::ScopedRoundingMode       VAR##_ctx_;                                             \
235         ::tcu::Interval&                        VAR##_dst_      = (DST);                        \
236         ::tcu::Interval                         VAR##_lo_;                                              \
237         ::tcu::Interval                         VAR##_hi_;                                              \
238                                                                                                                                 \
239         {                                                                                                                       \
240                 ::tcu::Interval&        VAR = VAR##_lo_;                                        \
241                 ::deSetRoundingMode(DE_ROUNDINGMODE_TO_NEGATIVE_INF);   \
242                 SETLOW;                                                                                                 \
243         }                                                                                                                       \
244         {                                                                                                                       \
245                 ::tcu::Interval&        VAR = VAR##_hi_;                                        \
246                 ::deSetRoundingMode(DE_ROUNDINGMODE_TO_POSITIVE_INF);   \
247                 SETHIGH;                                                                                                \
248         }                                                                                                                       \
249                                                                                                                                 \
250         VAR##_dst_ = VAR##_lo_ | VAR##_hi_;                                                     \
251 } while (::deGetFalse())
252
253 #define TCU_SET_INTERVAL(DST, VAR, BODY)                                                \
254         TCU_SET_INTERVAL_BOUNDS(DST, VAR, BODY, BODY)
255
256 //! Set the interval DST to the image of BODY on ARG, assuming that BODY on
257 //! ARG is a monotone function. In practice, BODY is evaluated on both the
258 //! upper and lower bound of ARG, and DST is set to the union of these
259 //! results. While evaluating BODY, PARAM is bound to the bound of ARG, and
260 //! the output of BODY should be stored in VAR.
261 #define TCU_INTERVAL_APPLY_MONOTONE1(DST, PARAM, ARG, VAR, BODY) do             \
262         {                                                                                                                                       \
263         const ::tcu::Interval&  VAR##_arg_              = (ARG);                                        \
264         ::tcu::Interval&                VAR##_dst_              = (DST);                                        \
265         ::tcu::Interval                 VAR##_lo_;                                                                      \
266         ::tcu::Interval                 VAR##_hi_;                                                                      \
267         if (VAR##_arg_.empty())                                                                                         \
268                 VAR##_dst_ = Interval();                                                                                \
269         else                                                                                                                            \
270         {                                                                                                                                       \
271                 {                                                                                                                               \
272                         const double            PARAM   = VAR##_arg_.lo();                              \
273                         ::tcu::Interval&        VAR             = VAR##_lo_;                                    \
274                         BODY;                                                                                                           \
275                 }                                                                                                                               \
276                 {                                                                                                                               \
277                         const double            PARAM   = VAR##_arg_.hi();                              \
278                         ::tcu::Interval&        VAR             = VAR##_hi_;                                    \
279                         BODY;                                                                                                           \
280                 }                                                                                                                               \
281                 VAR##_dst_ = VAR##_lo_ | VAR##_hi_;                                                             \
282         }                                                                                                                                       \
283         if (VAR##_arg_.hasNaN())                                                                                        \
284                 VAR##_dst_ |= TCU_NAN;                                                                                  \
285 } while (::deGetFalse())
286
287 #define TCU_INTERVAL_APPLY_MONOTONE2(DST, P0, A0, P1, A1, VAR, BODY)    \
288         TCU_INTERVAL_APPLY_MONOTONE1(                                                                           \
289                 DST, P0, A0, tmp2_,                                                                                             \
290                 TCU_INTERVAL_APPLY_MONOTONE1(tmp2_, P1, A1, VAR, BODY))
291
292 #define TCU_INTERVAL_APPLY_MONOTONE3(DST, P0, A0, P1, A1, P2, A2, VAR, BODY) \
293         TCU_INTERVAL_APPLY_MONOTONE1(                                                                           \
294                 DST, P0, A0, tmp3_,                                                                                             \
295                 TCU_INTERVAL_APPLY_MONOTONE2(tmp3_, P1, A1, P2, A2, VAR, BODY))
296
297 typedef double          DoubleFunc1                     (double);
298 typedef double          DoubleFunc2                     (double, double);
299 typedef double          DoubleFunc3                     (double, double, double);
300 typedef Interval        DoubleIntervalFunc1     (double);
301 typedef Interval        DoubleIntervalFunc2     (double, double);
302 typedef Interval        DoubleIntervalFunc3     (double, double, double);
303
304 Interval        applyMonotone   (DoubleFunc1&                   func,
305                                                          const Interval&                arg0);
306 Interval        applyMonotone   (DoubleFunc2&                   func,
307                                                          const Interval&                arg0,
308                                                          const Interval&                arg1);
309 Interval        applyMonotone   (DoubleIntervalFunc1&   func,
310                                                          const Interval&                arg0);
311 Interval        applyMonotone   (DoubleIntervalFunc2&   func,
312                                                          const Interval&                arg0,
313                                                          const Interval&                arg1);
314
315
316 } // tcu
317
318 #endif // _TCUINTERVAL_HPP