1e5c31af7Sopenharmony_ci/*------------------------------------------------------------------------- 2e5c31af7Sopenharmony_ci * drawElements Quality Program Tester Core 3e5c31af7Sopenharmony_ci * ---------------------------------------- 4e5c31af7Sopenharmony_ci * 5e5c31af7Sopenharmony_ci * Copyright 2014 The Android Open Source Project 6e5c31af7Sopenharmony_ci * 7e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 8e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License. 9e5c31af7Sopenharmony_ci * You may obtain a copy of the License at 10e5c31af7Sopenharmony_ci * 11e5c31af7Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 12e5c31af7Sopenharmony_ci * 13e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 14e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 15e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and 17e5c31af7Sopenharmony_ci * limitations under the License. 18e5c31af7Sopenharmony_ci * 19e5c31af7Sopenharmony_ci *//*! 20e5c31af7Sopenharmony_ci * \file 21e5c31af7Sopenharmony_ci * \brief Adjustable-precision floating point operations. 22e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/ 23e5c31af7Sopenharmony_ci 24e5c31af7Sopenharmony_ci#include "tcuFloatFormat.hpp" 25e5c31af7Sopenharmony_ci 26e5c31af7Sopenharmony_ci#include "deMath.h" 27e5c31af7Sopenharmony_ci#include "deUniquePtr.hpp" 28e5c31af7Sopenharmony_ci 29e5c31af7Sopenharmony_ci#include <sstream> 30e5c31af7Sopenharmony_ci#include <iomanip> 31e5c31af7Sopenharmony_ci#include <limits> 32e5c31af7Sopenharmony_ci 33e5c31af7Sopenharmony_cinamespace tcu 34e5c31af7Sopenharmony_ci{ 35e5c31af7Sopenharmony_cinamespace 36e5c31af7Sopenharmony_ci{ 37e5c31af7Sopenharmony_ci 38e5c31af7Sopenharmony_ciInterval chooseInterval(YesNoMaybe choice, const Interval& no, const Interval& yes) 39e5c31af7Sopenharmony_ci{ 40e5c31af7Sopenharmony_ci switch (choice) 41e5c31af7Sopenharmony_ci { 42e5c31af7Sopenharmony_ci case NO: return no; 43e5c31af7Sopenharmony_ci case YES: return yes; 44e5c31af7Sopenharmony_ci case MAYBE: return no | yes; 45e5c31af7Sopenharmony_ci default: DE_FATAL("Impossible case"); 46e5c31af7Sopenharmony_ci } 47e5c31af7Sopenharmony_ci 48e5c31af7Sopenharmony_ci return Interval(); 49e5c31af7Sopenharmony_ci} 50e5c31af7Sopenharmony_ci 51e5c31af7Sopenharmony_cidouble computeMaxValue (int maxExp, int fractionBits) 52e5c31af7Sopenharmony_ci{ 53e5c31af7Sopenharmony_ci return (deLdExp(1.0, maxExp) + 54e5c31af7Sopenharmony_ci deLdExp(double((1ull << fractionBits) - 1), maxExp - fractionBits)); 55e5c31af7Sopenharmony_ci} 56e5c31af7Sopenharmony_ci 57e5c31af7Sopenharmony_ci} // anonymous 58e5c31af7Sopenharmony_ci 59e5c31af7Sopenharmony_ciFloatFormat::FloatFormat (int minExp, 60e5c31af7Sopenharmony_ci int maxExp, 61e5c31af7Sopenharmony_ci int fractionBits, 62e5c31af7Sopenharmony_ci bool exactPrecision, 63e5c31af7Sopenharmony_ci YesNoMaybe hasSubnormal_, 64e5c31af7Sopenharmony_ci YesNoMaybe hasInf_, 65e5c31af7Sopenharmony_ci YesNoMaybe hasNaN_) 66e5c31af7Sopenharmony_ci : m_minExp (minExp) 67e5c31af7Sopenharmony_ci , m_maxExp (maxExp) 68e5c31af7Sopenharmony_ci , m_fractionBits (fractionBits) 69e5c31af7Sopenharmony_ci , m_hasSubnormal (hasSubnormal_) 70e5c31af7Sopenharmony_ci , m_hasInf (hasInf_) 71e5c31af7Sopenharmony_ci , m_hasNaN (hasNaN_) 72e5c31af7Sopenharmony_ci , m_exactPrecision (exactPrecision) 73e5c31af7Sopenharmony_ci , m_maxValue (computeMaxValue(maxExp, fractionBits)) 74e5c31af7Sopenharmony_ci{ 75e5c31af7Sopenharmony_ci DE_ASSERT(minExp <= maxExp); 76e5c31af7Sopenharmony_ci} 77e5c31af7Sopenharmony_ci 78e5c31af7Sopenharmony_ci/*------------------------------------------------------------------------- 79e5c31af7Sopenharmony_ci * On the definition of ULP 80e5c31af7Sopenharmony_ci * 81e5c31af7Sopenharmony_ci * The GLSL spec does not define ULP. However, it refers to IEEE 754, which 82e5c31af7Sopenharmony_ci * (reportedly) uses Harrison's definition: 83e5c31af7Sopenharmony_ci * 84e5c31af7Sopenharmony_ci * ULP(x) is the distance between the closest floating point numbers 85e5c31af7Sopenharmony_ci * a and be such that a <= x <= b and a != b 86e5c31af7Sopenharmony_ci * 87e5c31af7Sopenharmony_ci * Note that this means that when x = 2^n, ULP(x) = 2^(n-p-1), i.e. it is the 88e5c31af7Sopenharmony_ci * distance to the next lowest float, not next highest. 89e5c31af7Sopenharmony_ci * 90e5c31af7Sopenharmony_ci * Furthermore, it is assumed that ULP is calculated relative to the exact 91e5c31af7Sopenharmony_ci * value, not the approximation. This is because otherwise a less accurate 92e5c31af7Sopenharmony_ci * approximation could be closer in ULPs, because its ULPs are bigger. 93e5c31af7Sopenharmony_ci * 94e5c31af7Sopenharmony_ci * For details, see "On the definition of ulp(x)" by Jean-Michel Muller 95e5c31af7Sopenharmony_ci * 96e5c31af7Sopenharmony_ci *-----------------------------------------------------------------------*/ 97e5c31af7Sopenharmony_ci 98e5c31af7Sopenharmony_cidouble FloatFormat::ulp (double x, double count) const 99e5c31af7Sopenharmony_ci{ 100e5c31af7Sopenharmony_ci int exp = 0; 101e5c31af7Sopenharmony_ci const double frac = deFractExp(deAbs(x), &exp); 102e5c31af7Sopenharmony_ci 103e5c31af7Sopenharmony_ci if (deIsNaN(frac)) 104e5c31af7Sopenharmony_ci return TCU_NAN; 105e5c31af7Sopenharmony_ci else if (deIsInf(frac)) 106e5c31af7Sopenharmony_ci return deLdExp(1.0, m_maxExp - m_fractionBits); 107e5c31af7Sopenharmony_ci else if (frac == 1.0) 108e5c31af7Sopenharmony_ci { 109e5c31af7Sopenharmony_ci // Harrison's ULP: choose distance to closest (i.e. next lower) at binade 110e5c31af7Sopenharmony_ci // boundary. 111e5c31af7Sopenharmony_ci --exp; 112e5c31af7Sopenharmony_ci } 113e5c31af7Sopenharmony_ci else if (frac == 0.0) 114e5c31af7Sopenharmony_ci exp = m_minExp; 115e5c31af7Sopenharmony_ci 116e5c31af7Sopenharmony_ci // ULP cannot be lower than the smallest quantum. 117e5c31af7Sopenharmony_ci exp = de::max(exp, m_minExp); 118e5c31af7Sopenharmony_ci 119e5c31af7Sopenharmony_ci { 120e5c31af7Sopenharmony_ci const double oneULP = deLdExp(1.0, exp - m_fractionBits); 121e5c31af7Sopenharmony_ci ScopedRoundingMode ctx (DE_ROUNDINGMODE_TO_POSITIVE_INF); 122e5c31af7Sopenharmony_ci 123e5c31af7Sopenharmony_ci return oneULP * count; 124e5c31af7Sopenharmony_ci } 125e5c31af7Sopenharmony_ci} 126e5c31af7Sopenharmony_ci 127e5c31af7Sopenharmony_ci//! Return the difference between the given nominal exponent and 128e5c31af7Sopenharmony_ci//! the exponent of the lowest significand bit of the 129e5c31af7Sopenharmony_ci//! representation of a number with this format. 130e5c31af7Sopenharmony_ci//! For normal numbers this is the number of significand bits, but 131e5c31af7Sopenharmony_ci//! for subnormals it is less and for values of exp where 2^exp is too 132e5c31af7Sopenharmony_ci//! small to represent it is <0 133e5c31af7Sopenharmony_ciint FloatFormat::exponentShift (int exp) const 134e5c31af7Sopenharmony_ci{ 135e5c31af7Sopenharmony_ci return m_fractionBits - de::max(m_minExp - exp, 0); 136e5c31af7Sopenharmony_ci} 137e5c31af7Sopenharmony_ci 138e5c31af7Sopenharmony_ci//! Return the number closest to `d` that is exactly representable with the 139e5c31af7Sopenharmony_ci//! significand bits and minimum exponent of the floatformat. Round up if 140e5c31af7Sopenharmony_ci//! `upward` is true, otherwise down. 141e5c31af7Sopenharmony_cidouble FloatFormat::round (double d, bool upward) const 142e5c31af7Sopenharmony_ci{ 143e5c31af7Sopenharmony_ci int exp = 0; 144e5c31af7Sopenharmony_ci const double frac = deFractExp(d, &exp); 145e5c31af7Sopenharmony_ci const int shift = exponentShift(exp); 146e5c31af7Sopenharmony_ci const double shiftFrac = deLdExp(frac, shift); 147e5c31af7Sopenharmony_ci const double roundFrac = upward ? deCeil(shiftFrac) : deFloor(shiftFrac); 148e5c31af7Sopenharmony_ci 149e5c31af7Sopenharmony_ci return deLdExp(roundFrac, exp - shift); 150e5c31af7Sopenharmony_ci} 151e5c31af7Sopenharmony_ci 152e5c31af7Sopenharmony_ci//! Return the range of numbers that `d` might be converted to in the 153e5c31af7Sopenharmony_ci//! floatformat, given its limitations with infinities, subnormals and maximum 154e5c31af7Sopenharmony_ci//! exponent. 155e5c31af7Sopenharmony_ciInterval FloatFormat::clampValue (double d) const 156e5c31af7Sopenharmony_ci{ 157e5c31af7Sopenharmony_ci const double rSign = deSign(d); 158e5c31af7Sopenharmony_ci int rExp = 0; 159e5c31af7Sopenharmony_ci 160e5c31af7Sopenharmony_ci DE_ASSERT(!deIsNaN(d)); 161e5c31af7Sopenharmony_ci 162e5c31af7Sopenharmony_ci deFractExp(d, &rExp); 163e5c31af7Sopenharmony_ci if (rExp < m_minExp) 164e5c31af7Sopenharmony_ci return chooseInterval(m_hasSubnormal, rSign * 0.0, d); 165e5c31af7Sopenharmony_ci else if (deIsInf(d) || rExp > m_maxExp) 166e5c31af7Sopenharmony_ci return chooseInterval(m_hasInf, rSign * getMaxValue(), rSign * TCU_INFINITY); 167e5c31af7Sopenharmony_ci 168e5c31af7Sopenharmony_ci return Interval(d); 169e5c31af7Sopenharmony_ci} 170e5c31af7Sopenharmony_ci 171e5c31af7Sopenharmony_ci//! Return the range of numbers that might be used with this format to 172e5c31af7Sopenharmony_ci//! represent a number within `x`. 173e5c31af7Sopenharmony_ciInterval FloatFormat::convert (const Interval& x) const 174e5c31af7Sopenharmony_ci{ 175e5c31af7Sopenharmony_ci Interval ret; 176e5c31af7Sopenharmony_ci Interval tmp = x; 177e5c31af7Sopenharmony_ci 178e5c31af7Sopenharmony_ci if (x.hasNaN()) 179e5c31af7Sopenharmony_ci { 180e5c31af7Sopenharmony_ci // If NaN might be supported, NaN is a legal return value 181e5c31af7Sopenharmony_ci if (m_hasNaN != NO) 182e5c31af7Sopenharmony_ci ret |= TCU_NAN; 183e5c31af7Sopenharmony_ci 184e5c31af7Sopenharmony_ci // If NaN might not be supported, any (non-NaN) value is legal, 185e5c31af7Sopenharmony_ci // _subject_ to clamping. Hence we modify tmp, not ret. 186e5c31af7Sopenharmony_ci if (m_hasNaN != YES) 187e5c31af7Sopenharmony_ci tmp = Interval::unbounded(); 188e5c31af7Sopenharmony_ci } 189e5c31af7Sopenharmony_ci 190e5c31af7Sopenharmony_ci // Round both bounds _inwards_ to closest representable values. 191e5c31af7Sopenharmony_ci if (!tmp.empty()) 192e5c31af7Sopenharmony_ci ret |= clampValue(round(tmp.lo(), false)) | clampValue(round(tmp.hi(), true)); 193e5c31af7Sopenharmony_ci 194e5c31af7Sopenharmony_ci // If this format's precision is not exact, the (possibly out-of-bounds) 195e5c31af7Sopenharmony_ci // original value is also a possible result. 196e5c31af7Sopenharmony_ci if (!m_exactPrecision) 197e5c31af7Sopenharmony_ci ret |= x; 198e5c31af7Sopenharmony_ci 199e5c31af7Sopenharmony_ci return ret; 200e5c31af7Sopenharmony_ci} 201e5c31af7Sopenharmony_ci 202e5c31af7Sopenharmony_cidouble FloatFormat::roundOut (double d, bool upward, bool roundUnderOverflow) const 203e5c31af7Sopenharmony_ci{ 204e5c31af7Sopenharmony_ci int exp = 0; 205e5c31af7Sopenharmony_ci deFractExp(d, &exp); 206e5c31af7Sopenharmony_ci 207e5c31af7Sopenharmony_ci if (roundUnderOverflow && exp > m_maxExp && (upward == (d < 0.0))) 208e5c31af7Sopenharmony_ci return deSign(d) * getMaxValue(); 209e5c31af7Sopenharmony_ci else 210e5c31af7Sopenharmony_ci return round(d, upward); 211e5c31af7Sopenharmony_ci} 212e5c31af7Sopenharmony_ci 213e5c31af7Sopenharmony_ci//! Round output of an operation. 214e5c31af7Sopenharmony_ci//! \param roundUnderOverflow Can +/-inf rounded to min/max representable; 215e5c31af7Sopenharmony_ci//! should be false if any of operands was inf, true otherwise. 216e5c31af7Sopenharmony_ciInterval FloatFormat::roundOut (const Interval& x, bool roundUnderOverflow) const 217e5c31af7Sopenharmony_ci{ 218e5c31af7Sopenharmony_ci Interval ret = x.nan(); 219e5c31af7Sopenharmony_ci 220e5c31af7Sopenharmony_ci if (!x.empty()) 221e5c31af7Sopenharmony_ci ret |= Interval(roundOut(x.lo(), false, roundUnderOverflow), 222e5c31af7Sopenharmony_ci roundOut(x.hi(), true, roundUnderOverflow)); 223e5c31af7Sopenharmony_ci 224e5c31af7Sopenharmony_ci return ret; 225e5c31af7Sopenharmony_ci} 226e5c31af7Sopenharmony_ci 227e5c31af7Sopenharmony_cistd::string FloatFormat::floatToHex (double x) const 228e5c31af7Sopenharmony_ci{ 229e5c31af7Sopenharmony_ci if (deIsNaN(x)) 230e5c31af7Sopenharmony_ci return "NaN"; 231e5c31af7Sopenharmony_ci else if (deIsInf(x)) 232e5c31af7Sopenharmony_ci return (x < 0.0 ? "-" : "+") + std::string("inf"); 233e5c31af7Sopenharmony_ci else if (x == 0.0) // \todo [2014-03-27 lauri] Negative zero 234e5c31af7Sopenharmony_ci return "0.0"; 235e5c31af7Sopenharmony_ci 236e5c31af7Sopenharmony_ci int exp = 0; 237e5c31af7Sopenharmony_ci const double frac = deFractExp(deAbs(x), &exp); 238e5c31af7Sopenharmony_ci const int shift = exponentShift(exp); 239e5c31af7Sopenharmony_ci const deUint64 bits = deUint64(deLdExp(frac, shift)); 240e5c31af7Sopenharmony_ci const deUint64 whole = bits >> m_fractionBits; 241e5c31af7Sopenharmony_ci const deUint64 fraction = bits & ((deUint64(1) << m_fractionBits) - 1); 242e5c31af7Sopenharmony_ci const int exponent = exp + m_fractionBits - shift; 243e5c31af7Sopenharmony_ci const int numDigits = (m_fractionBits + 3) / 4; 244e5c31af7Sopenharmony_ci const deUint64 aligned = fraction << (numDigits * 4 - m_fractionBits); 245e5c31af7Sopenharmony_ci std::ostringstream oss; 246e5c31af7Sopenharmony_ci 247e5c31af7Sopenharmony_ci oss << (x < 0 ? "-" : "") 248e5c31af7Sopenharmony_ci << "0x" << whole << "." 249e5c31af7Sopenharmony_ci << std::hex << std::setw(numDigits) << std::setfill('0') << aligned 250e5c31af7Sopenharmony_ci << "p" << std::dec << std::setw(0) << exponent; 251e5c31af7Sopenharmony_ci 252e5c31af7Sopenharmony_ci return oss.str(); 253e5c31af7Sopenharmony_ci} 254e5c31af7Sopenharmony_ci 255e5c31af7Sopenharmony_cistd::string FloatFormat::intervalToHex (const Interval& interval) const 256e5c31af7Sopenharmony_ci{ 257e5c31af7Sopenharmony_ci if (interval.empty()) 258e5c31af7Sopenharmony_ci return interval.hasNaN() ? "{ NaN }" : "{}"; 259e5c31af7Sopenharmony_ci 260e5c31af7Sopenharmony_ci else if (interval.lo() == interval.hi()) 261e5c31af7Sopenharmony_ci return (std::string(interval.hasNaN() ? "{ NaN, " : "{ ") + 262e5c31af7Sopenharmony_ci floatToHex(interval.lo()) + " }"); 263e5c31af7Sopenharmony_ci else if (interval == Interval::unbounded(true)) 264e5c31af7Sopenharmony_ci return "<any>"; 265e5c31af7Sopenharmony_ci 266e5c31af7Sopenharmony_ci return (std::string(interval.hasNaN() ? "{ NaN } | " : "") + 267e5c31af7Sopenharmony_ci "[" + floatToHex(interval.lo()) + ", " + floatToHex(interval.hi()) + "]"); 268e5c31af7Sopenharmony_ci} 269e5c31af7Sopenharmony_ci 270e5c31af7Sopenharmony_citemplate <typename T> 271e5c31af7Sopenharmony_cistatic FloatFormat nativeFormat (void) 272e5c31af7Sopenharmony_ci{ 273e5c31af7Sopenharmony_ci typedef std::numeric_limits<T> Limits; 274e5c31af7Sopenharmony_ci 275e5c31af7Sopenharmony_ci DE_ASSERT(Limits::radix == 2); 276e5c31af7Sopenharmony_ci 277e5c31af7Sopenharmony_ci return FloatFormat(Limits::min_exponent - 1, // These have a built-in offset of one 278e5c31af7Sopenharmony_ci Limits::max_exponent - 1, 279e5c31af7Sopenharmony_ci Limits::digits - 1, // don't count the hidden bit 280e5c31af7Sopenharmony_ci Limits::has_denorm != std::denorm_absent, 281e5c31af7Sopenharmony_ci Limits::has_infinity ? YES : NO, 282e5c31af7Sopenharmony_ci Limits::has_quiet_NaN ? YES : NO, 283e5c31af7Sopenharmony_ci ((Limits::has_denorm == std::denorm_present) ? YES : 284e5c31af7Sopenharmony_ci (Limits::has_denorm == std::denorm_absent) ? NO : 285e5c31af7Sopenharmony_ci MAYBE)); 286e5c31af7Sopenharmony_ci} 287e5c31af7Sopenharmony_ci 288e5c31af7Sopenharmony_ciFloatFormat FloatFormat::nativeFloat (void) 289e5c31af7Sopenharmony_ci{ 290e5c31af7Sopenharmony_ci return nativeFormat<float>(); 291e5c31af7Sopenharmony_ci} 292e5c31af7Sopenharmony_ci 293e5c31af7Sopenharmony_ciFloatFormat FloatFormat::nativeDouble (void) 294e5c31af7Sopenharmony_ci{ 295e5c31af7Sopenharmony_ci return nativeFormat<double>(); 296e5c31af7Sopenharmony_ci} 297e5c31af7Sopenharmony_ci 298e5c31af7Sopenharmony_ciNormalizedFormat::NormalizedFormat (int fractionBits) 299e5c31af7Sopenharmony_ci : FloatFormat(0, 0, fractionBits, true, tcu::YES) 300e5c31af7Sopenharmony_ci{ 301e5c31af7Sopenharmony_ci 302e5c31af7Sopenharmony_ci} 303e5c31af7Sopenharmony_ci 304e5c31af7Sopenharmony_cidouble NormalizedFormat::round(double d, bool upward) const 305e5c31af7Sopenharmony_ci{ 306e5c31af7Sopenharmony_ci const int fractionBits = getFractionBits(); 307e5c31af7Sopenharmony_ci 308e5c31af7Sopenharmony_ci if (fractionBits <= 0) 309e5c31af7Sopenharmony_ci return d; 310e5c31af7Sopenharmony_ci 311e5c31af7Sopenharmony_ci const int maxIntValue = (1 << fractionBits) - 1; 312e5c31af7Sopenharmony_ci const double value = d * maxIntValue; 313e5c31af7Sopenharmony_ci const double normValue = upward ? deCeil(value) : deFloor(value); 314e5c31af7Sopenharmony_ci return normValue / maxIntValue; 315e5c31af7Sopenharmony_ci} 316e5c31af7Sopenharmony_ci 317e5c31af7Sopenharmony_cidouble NormalizedFormat::ulp(double x, double count) const 318e5c31af7Sopenharmony_ci{ 319e5c31af7Sopenharmony_ci (void) x; 320e5c31af7Sopenharmony_ci 321e5c31af7Sopenharmony_ci const int maxIntValue = (1 << getFractionBits()) - 1; 322e5c31af7Sopenharmony_ci const double precision = 1.0 / maxIntValue; 323e5c31af7Sopenharmony_ci return precision * count; 324e5c31af7Sopenharmony_ci} 325e5c31af7Sopenharmony_ci 326e5c31af7Sopenharmony_cidouble NormalizedFormat::roundOut (double d, bool upward, bool roundUnderOverflow) const 327e5c31af7Sopenharmony_ci{ 328e5c31af7Sopenharmony_ci if (roundUnderOverflow && deAbs(d) > 1.0 && (upward == (d < 0.0))) 329e5c31af7Sopenharmony_ci return deSign(d); 330e5c31af7Sopenharmony_ci else 331e5c31af7Sopenharmony_ci return round(d, upward); 332e5c31af7Sopenharmony_ci} 333e5c31af7Sopenharmony_ci 334e5c31af7Sopenharmony_cinamespace 335e5c31af7Sopenharmony_ci{ 336e5c31af7Sopenharmony_ci 337e5c31af7Sopenharmony_ciusing std::string; 338e5c31af7Sopenharmony_ciusing std::ostringstream; 339e5c31af7Sopenharmony_ciusing de::MovePtr; 340e5c31af7Sopenharmony_ciusing de::UniquePtr; 341e5c31af7Sopenharmony_ci 342e5c31af7Sopenharmony_ciclass Test 343e5c31af7Sopenharmony_ci{ 344e5c31af7Sopenharmony_ciprotected: 345e5c31af7Sopenharmony_ci 346e5c31af7Sopenharmony_ci Test (MovePtr<FloatFormat> fmt) : m_fmt(fmt) {} 347e5c31af7Sopenharmony_ci double p (int e) const { return deLdExp(1.0, e); } 348e5c31af7Sopenharmony_ci void check (const string& expr, 349e5c31af7Sopenharmony_ci double result, 350e5c31af7Sopenharmony_ci double reference) const; 351e5c31af7Sopenharmony_ci void testULP (double arg, double ref) const; 352e5c31af7Sopenharmony_ci void testRound (double arg, double refDown, double refUp) const; 353e5c31af7Sopenharmony_ci 354e5c31af7Sopenharmony_ci UniquePtr<FloatFormat> m_fmt; 355e5c31af7Sopenharmony_ci}; 356e5c31af7Sopenharmony_ci 357e5c31af7Sopenharmony_civoid Test::check (const string& expr, double result, double reference) const 358e5c31af7Sopenharmony_ci{ 359e5c31af7Sopenharmony_ci if (result != reference) 360e5c31af7Sopenharmony_ci { 361e5c31af7Sopenharmony_ci ostringstream oss; 362e5c31af7Sopenharmony_ci oss << expr << " returned " << result << ", expected " << reference; 363e5c31af7Sopenharmony_ci TCU_FAIL(oss.str().c_str()); 364e5c31af7Sopenharmony_ci } 365e5c31af7Sopenharmony_ci} 366e5c31af7Sopenharmony_ci 367e5c31af7Sopenharmony_civoid Test::testULP (double arg, double ref) const 368e5c31af7Sopenharmony_ci{ 369e5c31af7Sopenharmony_ci ostringstream oss; 370e5c31af7Sopenharmony_ci 371e5c31af7Sopenharmony_ci oss << "ulp(" << arg << ")"; 372e5c31af7Sopenharmony_ci check(oss.str(), m_fmt->ulp(arg), ref); 373e5c31af7Sopenharmony_ci} 374e5c31af7Sopenharmony_ci 375e5c31af7Sopenharmony_civoid Test::testRound (double arg, double refDown, double refUp) const 376e5c31af7Sopenharmony_ci{ 377e5c31af7Sopenharmony_ci { 378e5c31af7Sopenharmony_ci ostringstream oss; 379e5c31af7Sopenharmony_ci oss << "round(" << arg << ", false)"; 380e5c31af7Sopenharmony_ci check(oss.str(), m_fmt->round(arg, false), refDown); 381e5c31af7Sopenharmony_ci } 382e5c31af7Sopenharmony_ci { 383e5c31af7Sopenharmony_ci ostringstream oss; 384e5c31af7Sopenharmony_ci oss << "round(" << arg << ", true)"; 385e5c31af7Sopenharmony_ci check(oss.str(), m_fmt->round(arg, true), refUp); 386e5c31af7Sopenharmony_ci } 387e5c31af7Sopenharmony_ci} 388e5c31af7Sopenharmony_ci 389e5c31af7Sopenharmony_ciclass TestBinary32 : public Test 390e5c31af7Sopenharmony_ci{ 391e5c31af7Sopenharmony_cipublic: 392e5c31af7Sopenharmony_ci TestBinary32 (void) 393e5c31af7Sopenharmony_ci : Test (MovePtr<FloatFormat>(new FloatFormat(-126, 127, 23, true))) {} 394e5c31af7Sopenharmony_ci 395e5c31af7Sopenharmony_ci void runTest (void) const; 396e5c31af7Sopenharmony_ci}; 397e5c31af7Sopenharmony_ci 398e5c31af7Sopenharmony_civoid TestBinary32::runTest (void) const 399e5c31af7Sopenharmony_ci{ 400e5c31af7Sopenharmony_ci testULP(p(0), p(-24)); 401e5c31af7Sopenharmony_ci testULP(p(0) + p(-23), p(-23)); 402e5c31af7Sopenharmony_ci testULP(p(-124), p(-148)); 403e5c31af7Sopenharmony_ci testULP(p(-125), p(-149)); 404e5c31af7Sopenharmony_ci testULP(p(-125) + p(-140), p(-148)); 405e5c31af7Sopenharmony_ci testULP(p(-126), p(-149)); 406e5c31af7Sopenharmony_ci testULP(p(-130), p(-149)); 407e5c31af7Sopenharmony_ci 408e5c31af7Sopenharmony_ci testRound(p(0) + p(-20) + p(-40), p(0) + p(-20), p(0) + p(-20) + p(-23)); 409e5c31af7Sopenharmony_ci testRound(p(-126) - p(-150), p(-126) - p(-149), p(-126)); 410e5c31af7Sopenharmony_ci 411e5c31af7Sopenharmony_ci TCU_CHECK(m_fmt->floatToHex(p(0)) == "0x1.000000p0"); 412e5c31af7Sopenharmony_ci TCU_CHECK(m_fmt->floatToHex(p(8) + p(-4)) == "0x1.001000p8"); 413e5c31af7Sopenharmony_ci TCU_CHECK(m_fmt->floatToHex(p(-140)) == "0x0.000400p-126"); 414e5c31af7Sopenharmony_ci TCU_CHECK(m_fmt->floatToHex(p(-140)) == "0x0.000400p-126"); 415e5c31af7Sopenharmony_ci TCU_CHECK(m_fmt->floatToHex(p(-126) + p(-125)) == "0x1.800000p-125"); 416e5c31af7Sopenharmony_ci} 417e5c31af7Sopenharmony_ci 418e5c31af7Sopenharmony_ci} // anonymous 419e5c31af7Sopenharmony_ci 420e5c31af7Sopenharmony_civoid FloatFormat_selfTest (void) 421e5c31af7Sopenharmony_ci{ 422e5c31af7Sopenharmony_ci TestBinary32 test32; 423e5c31af7Sopenharmony_ci test32.runTest(); 424e5c31af7Sopenharmony_ci} 425e5c31af7Sopenharmony_ci 426e5c31af7Sopenharmony_ci} // tcu 427