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