1e5c31af7Sopenharmony_ci#ifndef _TCUINTERVAL_HPP 2e5c31af7Sopenharmony_ci#define _TCUINTERVAL_HPP 3e5c31af7Sopenharmony_ci/*------------------------------------------------------------------------- 4e5c31af7Sopenharmony_ci * drawElements Quality Program Tester Core 5e5c31af7Sopenharmony_ci * ---------------------------------------- 6e5c31af7Sopenharmony_ci * 7e5c31af7Sopenharmony_ci * Copyright 2014 The Android Open Source Project 8e5c31af7Sopenharmony_ci * 9e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 10e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License. 11e5c31af7Sopenharmony_ci * You may obtain a copy of the License at 12e5c31af7Sopenharmony_ci * 13e5c31af7Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 14e5c31af7Sopenharmony_ci * 15e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 16e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 17e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and 19e5c31af7Sopenharmony_ci * limitations under the License. 20e5c31af7Sopenharmony_ci * 21e5c31af7Sopenharmony_ci *//*! 22e5c31af7Sopenharmony_ci * \file 23e5c31af7Sopenharmony_ci * \brief Interval arithmetic and floating point precisions. 24e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/ 25e5c31af7Sopenharmony_ci 26e5c31af7Sopenharmony_ci#include "tcuDefs.hpp" 27e5c31af7Sopenharmony_ci 28e5c31af7Sopenharmony_ci#include "deMath.h" 29e5c31af7Sopenharmony_ci 30e5c31af7Sopenharmony_ci#include <iostream> 31e5c31af7Sopenharmony_ci#include <limits> 32e5c31af7Sopenharmony_ci#include <cmath> 33e5c31af7Sopenharmony_ci 34e5c31af7Sopenharmony_ci#define TCU_INFINITY (::std::numeric_limits<float>::infinity()) 35e5c31af7Sopenharmony_ci#define TCU_NAN (::std::numeric_limits<float>::quiet_NaN()) 36e5c31af7Sopenharmony_ci 37e5c31af7Sopenharmony_cinamespace tcu 38e5c31af7Sopenharmony_ci{ 39e5c31af7Sopenharmony_ci 40e5c31af7Sopenharmony_ci// RAII context for temporarily changing the rounding mode 41e5c31af7Sopenharmony_ciclass ScopedRoundingMode 42e5c31af7Sopenharmony_ci{ 43e5c31af7Sopenharmony_cipublic: 44e5c31af7Sopenharmony_ci ScopedRoundingMode (deRoundingMode mode) 45e5c31af7Sopenharmony_ci : m_oldMode (deGetRoundingMode()) { deSetRoundingMode(mode); } 46e5c31af7Sopenharmony_ci 47e5c31af7Sopenharmony_ci ScopedRoundingMode (void) : m_oldMode (deGetRoundingMode()) {} 48e5c31af7Sopenharmony_ci 49e5c31af7Sopenharmony_ci ~ScopedRoundingMode (void) { deSetRoundingMode(m_oldMode); } 50e5c31af7Sopenharmony_ci 51e5c31af7Sopenharmony_ciprivate: 52e5c31af7Sopenharmony_ci ScopedRoundingMode (const ScopedRoundingMode&); 53e5c31af7Sopenharmony_ci ScopedRoundingMode& operator= (const ScopedRoundingMode&); 54e5c31af7Sopenharmony_ci 55e5c31af7Sopenharmony_ci const deRoundingMode m_oldMode; 56e5c31af7Sopenharmony_ci}; 57e5c31af7Sopenharmony_ci 58e5c31af7Sopenharmony_ciclass Interval 59e5c31af7Sopenharmony_ci{ 60e5c31af7Sopenharmony_cipublic: 61e5c31af7Sopenharmony_ci // Empty interval. 62e5c31af7Sopenharmony_ci Interval (void) 63e5c31af7Sopenharmony_ci : m_hasNaN (false) 64e5c31af7Sopenharmony_ci , m_lo (TCU_INFINITY) 65e5c31af7Sopenharmony_ci , m_hi (-TCU_INFINITY) 66e5c31af7Sopenharmony_ci , m_warningLo (-TCU_INFINITY) 67e5c31af7Sopenharmony_ci , m_warningHi (TCU_INFINITY) {} 68e5c31af7Sopenharmony_ci 69e5c31af7Sopenharmony_ci // Intentionally not explicit. Conversion from double to Interval is common 70e5c31af7Sopenharmony_ci // and reasonable. 71e5c31af7Sopenharmony_ci Interval (double val) 72e5c31af7Sopenharmony_ci : m_hasNaN (!!deIsNaN(val)) 73e5c31af7Sopenharmony_ci , m_lo (m_hasNaN ? TCU_INFINITY : val) 74e5c31af7Sopenharmony_ci , m_hi (m_hasNaN ? -TCU_INFINITY : val) 75e5c31af7Sopenharmony_ci , m_warningLo (-TCU_INFINITY) 76e5c31af7Sopenharmony_ci , m_warningHi (TCU_INFINITY) {} 77e5c31af7Sopenharmony_ci 78e5c31af7Sopenharmony_ci 79e5c31af7Sopenharmony_ci Interval(bool hasNaN_, double lo_, double hi_) 80e5c31af7Sopenharmony_ci : m_hasNaN(hasNaN_), m_lo(lo_), m_hi(hi_), m_warningLo(-TCU_INFINITY), m_warningHi(TCU_INFINITY) {} 81e5c31af7Sopenharmony_ci 82e5c31af7Sopenharmony_ci Interval(bool hasNaN_, double lo_, double hi_, double wlo_, double whi_) 83e5c31af7Sopenharmony_ci : m_hasNaN(hasNaN_), m_lo(lo_), m_hi(hi_), m_warningLo(wlo_), m_warningHi(whi_) {} 84e5c31af7Sopenharmony_ci 85e5c31af7Sopenharmony_ci Interval (const Interval& a, const Interval& b) 86e5c31af7Sopenharmony_ci : m_hasNaN (a.m_hasNaN || b.m_hasNaN) 87e5c31af7Sopenharmony_ci , m_lo (de::min(a.lo(), b.lo())) 88e5c31af7Sopenharmony_ci , m_hi (de::max(a.hi(), b.hi())) 89e5c31af7Sopenharmony_ci , m_warningLo (de::min(a.warningLo(), b.warningLo())) 90e5c31af7Sopenharmony_ci , m_warningHi (de::max(a.warningHi(), b.warningHi())) {} 91e5c31af7Sopenharmony_ci 92e5c31af7Sopenharmony_ci double length (void) const { return m_hi - m_lo; } 93e5c31af7Sopenharmony_ci double lo (void) const { return m_lo; } 94e5c31af7Sopenharmony_ci double hi (void) const { return m_hi; } 95e5c31af7Sopenharmony_ci double warningLo (void) const { return m_warningLo; } 96e5c31af7Sopenharmony_ci double warningHi (void) const { return m_warningHi; } 97e5c31af7Sopenharmony_ci bool hasNaN (void) const { return m_hasNaN; } 98e5c31af7Sopenharmony_ci Interval nan (void) const { return m_hasNaN ? TCU_NAN : Interval(); } 99e5c31af7Sopenharmony_ci bool empty (void) const { return m_lo > m_hi; } 100e5c31af7Sopenharmony_ci 101e5c31af7Sopenharmony_ci // The interval is represented in double, it can extend outside the range of smaller floating-point formats 102e5c31af7Sopenharmony_ci // and get rounded to infinity. 103e5c31af7Sopenharmony_ci bool isFinite (double maxValue) const { return m_lo > -maxValue && m_hi < maxValue; } 104e5c31af7Sopenharmony_ci bool isOrdinary (double maxValue) const { return !hasNaN() && !empty() && isFinite(maxValue); } 105e5c31af7Sopenharmony_ci 106e5c31af7Sopenharmony_ci void warning (double lo_, double hi_) 107e5c31af7Sopenharmony_ci { 108e5c31af7Sopenharmony_ci m_warningLo = lo_; 109e5c31af7Sopenharmony_ci m_warningHi = hi_; 110e5c31af7Sopenharmony_ci } 111e5c31af7Sopenharmony_ci 112e5c31af7Sopenharmony_ci Interval operator| (const Interval& other) const 113e5c31af7Sopenharmony_ci { 114e5c31af7Sopenharmony_ci return Interval(m_hasNaN || other.m_hasNaN, 115e5c31af7Sopenharmony_ci de::min(m_lo, other.m_lo), 116e5c31af7Sopenharmony_ci de::max(m_hi, other.m_hi), 117e5c31af7Sopenharmony_ci de::min(m_warningLo, other.m_warningLo), 118e5c31af7Sopenharmony_ci de::max(m_warningHi, other.m_warningHi)); 119e5c31af7Sopenharmony_ci } 120e5c31af7Sopenharmony_ci 121e5c31af7Sopenharmony_ci Interval& operator|= (const Interval& other) 122e5c31af7Sopenharmony_ci { 123e5c31af7Sopenharmony_ci return (*this = *this | other); 124e5c31af7Sopenharmony_ci } 125e5c31af7Sopenharmony_ci 126e5c31af7Sopenharmony_ci Interval operator& (const Interval& other) const 127e5c31af7Sopenharmony_ci { 128e5c31af7Sopenharmony_ci return Interval(m_hasNaN && other.m_hasNaN, 129e5c31af7Sopenharmony_ci de::max(m_lo, other.m_lo), 130e5c31af7Sopenharmony_ci de::min(m_hi, other.m_hi), 131e5c31af7Sopenharmony_ci de::max(m_warningLo, other.m_warningLo), 132e5c31af7Sopenharmony_ci de::min(m_warningHi, other.m_warningHi)); 133e5c31af7Sopenharmony_ci } 134e5c31af7Sopenharmony_ci 135e5c31af7Sopenharmony_ci Interval& operator&= (const Interval& other) 136e5c31af7Sopenharmony_ci { 137e5c31af7Sopenharmony_ci return (*this = *this & other); 138e5c31af7Sopenharmony_ci } 139e5c31af7Sopenharmony_ci 140e5c31af7Sopenharmony_ci bool contains (const Interval& other) const 141e5c31af7Sopenharmony_ci { 142e5c31af7Sopenharmony_ci return (other.lo() >= lo() && other.hi() <= hi() && 143e5c31af7Sopenharmony_ci (!other.hasNaN() || hasNaN())); 144e5c31af7Sopenharmony_ci } 145e5c31af7Sopenharmony_ci 146e5c31af7Sopenharmony_ci bool containsWarning(const Interval& other) const 147e5c31af7Sopenharmony_ci { 148e5c31af7Sopenharmony_ci return (other.lo() >= warningLo() && other.hi() <= warningHi() && 149e5c31af7Sopenharmony_ci (!other.hasNaN() || hasNaN())); 150e5c31af7Sopenharmony_ci } 151e5c31af7Sopenharmony_ci 152e5c31af7Sopenharmony_ci bool intersects (const Interval& other) const 153e5c31af7Sopenharmony_ci { 154e5c31af7Sopenharmony_ci return ((other.hi() >= lo() && other.lo() <= hi()) || 155e5c31af7Sopenharmony_ci (other.hasNaN() && hasNaN())); 156e5c31af7Sopenharmony_ci } 157e5c31af7Sopenharmony_ci 158e5c31af7Sopenharmony_ci Interval operator- (void) const 159e5c31af7Sopenharmony_ci { 160e5c31af7Sopenharmony_ci return Interval(hasNaN(), -hi(), -lo(), -warningHi(), -warningLo()); 161e5c31af7Sopenharmony_ci } 162e5c31af7Sopenharmony_ci 163e5c31af7Sopenharmony_ci static Interval unbounded (bool nan = false) 164e5c31af7Sopenharmony_ci { 165e5c31af7Sopenharmony_ci return Interval(nan, -TCU_INFINITY, TCU_INFINITY); 166e5c31af7Sopenharmony_ci } 167e5c31af7Sopenharmony_ci 168e5c31af7Sopenharmony_ci double midpoint (void) const 169e5c31af7Sopenharmony_ci { 170e5c31af7Sopenharmony_ci const double h = hi(); 171e5c31af7Sopenharmony_ci const double l = lo(); 172e5c31af7Sopenharmony_ci 173e5c31af7Sopenharmony_ci if (h == -l) 174e5c31af7Sopenharmony_ci return 0.0; 175e5c31af7Sopenharmony_ci if (l == -TCU_INFINITY) 176e5c31af7Sopenharmony_ci return -TCU_INFINITY; 177e5c31af7Sopenharmony_ci if (h == TCU_INFINITY) 178e5c31af7Sopenharmony_ci return TCU_INFINITY; 179e5c31af7Sopenharmony_ci 180e5c31af7Sopenharmony_ci const bool negativeH = ::std::signbit(h); 181e5c31af7Sopenharmony_ci const bool negativeL = ::std::signbit(l); 182e5c31af7Sopenharmony_ci double ret; 183e5c31af7Sopenharmony_ci 184e5c31af7Sopenharmony_ci if (negativeH != negativeL) 185e5c31af7Sopenharmony_ci { 186e5c31af7Sopenharmony_ci // Different signs. Adding both values should be safe. 187e5c31af7Sopenharmony_ci ret = (h + l) * 0.5; 188e5c31af7Sopenharmony_ci } 189e5c31af7Sopenharmony_ci else 190e5c31af7Sopenharmony_ci { 191e5c31af7Sopenharmony_ci // Same sign. Substracting low from high should be safe. 192e5c31af7Sopenharmony_ci ret = l + (h - l) * 0.5; 193e5c31af7Sopenharmony_ci } 194e5c31af7Sopenharmony_ci 195e5c31af7Sopenharmony_ci return ret; 196e5c31af7Sopenharmony_ci } 197e5c31af7Sopenharmony_ci 198e5c31af7Sopenharmony_ci bool operator== (const Interval& other) const 199e5c31af7Sopenharmony_ci { 200e5c31af7Sopenharmony_ci return ((m_hasNaN == other.m_hasNaN) && 201e5c31af7Sopenharmony_ci ((empty() && other.empty()) || 202e5c31af7Sopenharmony_ci (m_lo == other.m_lo && m_hi == other.m_hi))); 203e5c31af7Sopenharmony_ci } 204e5c31af7Sopenharmony_ci 205e5c31af7Sopenharmony_ciprivate: 206e5c31af7Sopenharmony_ci bool m_hasNaN; 207e5c31af7Sopenharmony_ci double m_lo; 208e5c31af7Sopenharmony_ci double m_hi; 209e5c31af7Sopenharmony_ci double m_warningLo; 210e5c31af7Sopenharmony_ci double m_warningHi; 211e5c31af7Sopenharmony_ci} DE_WARN_UNUSED_TYPE; 212e5c31af7Sopenharmony_ci 213e5c31af7Sopenharmony_ciinline Interval operator+ (const Interval& x) { return x; } 214e5c31af7Sopenharmony_ciInterval exp2 (const Interval& x); 215e5c31af7Sopenharmony_ciInterval exp (const Interval& x); 216e5c31af7Sopenharmony_ciint sign (const Interval& x); 217e5c31af7Sopenharmony_ciInterval abs (const Interval& x); 218e5c31af7Sopenharmony_ciInterval inverseSqrt (const Interval& x); 219e5c31af7Sopenharmony_ci 220e5c31af7Sopenharmony_ciInterval operator+ (const Interval& x, const Interval& y); 221e5c31af7Sopenharmony_ciInterval operator- (const Interval& x, const Interval& y); 222e5c31af7Sopenharmony_ciInterval operator* (const Interval& x, const Interval& y); 223e5c31af7Sopenharmony_ciInterval operator/ (const Interval& nom, const Interval& den); 224e5c31af7Sopenharmony_ci 225e5c31af7Sopenharmony_ciinline Interval& operator+= (Interval& x, const Interval& y) { return (x = x + y); } 226e5c31af7Sopenharmony_ciinline Interval& operator-= (Interval& x, const Interval& y) { return (x = x - y); } 227e5c31af7Sopenharmony_ciinline Interval& operator*= (Interval& x, const Interval& y) { return (x = x * y); } 228e5c31af7Sopenharmony_ciinline Interval& operator/= (Interval& x, const Interval& y) { return (x = x / y); } 229e5c31af7Sopenharmony_ci 230e5c31af7Sopenharmony_cistd::ostream& operator<< (std::ostream& os, const Interval& interval); 231e5c31af7Sopenharmony_ci 232e5c31af7Sopenharmony_ci#define TCU_SET_INTERVAL_BOUNDS(DST, VAR, SETLOW, SETHIGH) do \ 233e5c31af7Sopenharmony_ci{ \ 234e5c31af7Sopenharmony_ci DE_FENV_ACCESS_ON \ 235e5c31af7Sopenharmony_ci ::tcu::ScopedRoundingMode VAR##_ctx_; \ 236e5c31af7Sopenharmony_ci ::tcu::Interval& VAR##_dst_ = (DST); \ 237e5c31af7Sopenharmony_ci ::tcu::Interval VAR##_lo_; \ 238e5c31af7Sopenharmony_ci ::tcu::Interval VAR##_hi_; \ 239e5c31af7Sopenharmony_ci \ 240e5c31af7Sopenharmony_ci { \ 241e5c31af7Sopenharmony_ci ::tcu::Interval& VAR = VAR##_lo_; \ 242e5c31af7Sopenharmony_ci ::deSetRoundingMode(DE_ROUNDINGMODE_TO_NEGATIVE_INF); \ 243e5c31af7Sopenharmony_ci SETLOW; \ 244e5c31af7Sopenharmony_ci } \ 245e5c31af7Sopenharmony_ci { \ 246e5c31af7Sopenharmony_ci ::tcu::Interval& VAR = VAR##_hi_; \ 247e5c31af7Sopenharmony_ci ::deSetRoundingMode(DE_ROUNDINGMODE_TO_POSITIVE_INF); \ 248e5c31af7Sopenharmony_ci SETHIGH; \ 249e5c31af7Sopenharmony_ci } \ 250e5c31af7Sopenharmony_ci \ 251e5c31af7Sopenharmony_ci VAR##_dst_ = VAR##_lo_ | VAR##_hi_; \ 252e5c31af7Sopenharmony_ci} while (::deGetFalse()) 253e5c31af7Sopenharmony_ci 254e5c31af7Sopenharmony_ci#define TCU_SET_INTERVAL(DST, VAR, BODY) \ 255e5c31af7Sopenharmony_ci TCU_SET_INTERVAL_BOUNDS(DST, VAR, BODY, BODY) 256e5c31af7Sopenharmony_ci 257e5c31af7Sopenharmony_ci//! Set the interval DST to the image of BODY on ARG, assuming that BODY on 258e5c31af7Sopenharmony_ci//! ARG is a monotone function. In practice, BODY is evaluated on both the 259e5c31af7Sopenharmony_ci//! upper and lower bound of ARG, and DST is set to the union of these 260e5c31af7Sopenharmony_ci//! results. While evaluating BODY, PARAM is bound to the bound of ARG, and 261e5c31af7Sopenharmony_ci//! the output of BODY should be stored in VAR. 262e5c31af7Sopenharmony_ci#define TCU_INTERVAL_APPLY_MONOTONE1(DST, PARAM, ARG, VAR, BODY) do \ 263e5c31af7Sopenharmony_ci { \ 264e5c31af7Sopenharmony_ci const ::tcu::Interval& VAR##_arg_ = (ARG); \ 265e5c31af7Sopenharmony_ci ::tcu::Interval& VAR##_dst_ = (DST); \ 266e5c31af7Sopenharmony_ci ::tcu::Interval VAR##_lo_; \ 267e5c31af7Sopenharmony_ci ::tcu::Interval VAR##_hi_; \ 268e5c31af7Sopenharmony_ci if (VAR##_arg_.empty()) \ 269e5c31af7Sopenharmony_ci VAR##_dst_ = Interval(); \ 270e5c31af7Sopenharmony_ci else \ 271e5c31af7Sopenharmony_ci { \ 272e5c31af7Sopenharmony_ci { \ 273e5c31af7Sopenharmony_ci const double PARAM = VAR##_arg_.lo(); \ 274e5c31af7Sopenharmony_ci ::tcu::Interval& VAR = VAR##_lo_; \ 275e5c31af7Sopenharmony_ci BODY; \ 276e5c31af7Sopenharmony_ci } \ 277e5c31af7Sopenharmony_ci { \ 278e5c31af7Sopenharmony_ci const double PARAM = VAR##_arg_.hi(); \ 279e5c31af7Sopenharmony_ci ::tcu::Interval& VAR = VAR##_hi_; \ 280e5c31af7Sopenharmony_ci BODY; \ 281e5c31af7Sopenharmony_ci } \ 282e5c31af7Sopenharmony_ci VAR##_dst_ = VAR##_lo_ | VAR##_hi_; \ 283e5c31af7Sopenharmony_ci } \ 284e5c31af7Sopenharmony_ci if (VAR##_arg_.hasNaN()) \ 285e5c31af7Sopenharmony_ci VAR##_dst_ |= TCU_NAN; \ 286e5c31af7Sopenharmony_ci} while (::deGetFalse()) 287e5c31af7Sopenharmony_ci 288e5c31af7Sopenharmony_ci#define TCU_INTERVAL_APPLY_MONOTONE2(DST, P0, A0, P1, A1, VAR, BODY) \ 289e5c31af7Sopenharmony_ci TCU_INTERVAL_APPLY_MONOTONE1( \ 290e5c31af7Sopenharmony_ci DST, P0, A0, tmp2_, \ 291e5c31af7Sopenharmony_ci TCU_INTERVAL_APPLY_MONOTONE1(tmp2_, P1, A1, VAR, BODY)) 292e5c31af7Sopenharmony_ci 293e5c31af7Sopenharmony_ci#define TCU_INTERVAL_APPLY_MONOTONE3(DST, P0, A0, P1, A1, P2, A2, VAR, BODY) \ 294e5c31af7Sopenharmony_ci TCU_INTERVAL_APPLY_MONOTONE1( \ 295e5c31af7Sopenharmony_ci DST, P0, A0, tmp3_, \ 296e5c31af7Sopenharmony_ci TCU_INTERVAL_APPLY_MONOTONE2(tmp3_, P1, A1, P2, A2, VAR, BODY)) 297e5c31af7Sopenharmony_ci 298e5c31af7Sopenharmony_citypedef double DoubleFunc1 (double); 299e5c31af7Sopenharmony_citypedef double DoubleFunc2 (double, double); 300e5c31af7Sopenharmony_citypedef double DoubleFunc3 (double, double, double); 301e5c31af7Sopenharmony_citypedef Interval DoubleIntervalFunc1 (double); 302e5c31af7Sopenharmony_citypedef Interval DoubleIntervalFunc2 (double, double); 303e5c31af7Sopenharmony_citypedef Interval DoubleIntervalFunc3 (double, double, double); 304e5c31af7Sopenharmony_ci 305e5c31af7Sopenharmony_ciInterval applyMonotone (DoubleFunc1& func, 306e5c31af7Sopenharmony_ci const Interval& arg0); 307e5c31af7Sopenharmony_ciInterval applyMonotone (DoubleFunc2& func, 308e5c31af7Sopenharmony_ci const Interval& arg0, 309e5c31af7Sopenharmony_ci const Interval& arg1); 310e5c31af7Sopenharmony_ciInterval applyMonotone (DoubleIntervalFunc1& func, 311e5c31af7Sopenharmony_ci const Interval& arg0); 312e5c31af7Sopenharmony_ciInterval applyMonotone (DoubleIntervalFunc2& func, 313e5c31af7Sopenharmony_ci const Interval& arg0, 314e5c31af7Sopenharmony_ci const Interval& arg1); 315e5c31af7Sopenharmony_ci 316e5c31af7Sopenharmony_ci 317e5c31af7Sopenharmony_ci} // tcu 318e5c31af7Sopenharmony_ci 319e5c31af7Sopenharmony_ci#endif // _TCUINTERVAL_HPP 320