diff --git a/projects/hip-tests/catch/hipTestMain/config/config_amd_linux b/projects/hip-tests/catch/hipTestMain/config/config_amd_linux index 5413570155..6a168deafe 100644 --- a/projects/hip-tests/catch/hipTestMain/config/config_amd_linux +++ b/projects/hip-tests/catch/hipTestMain/config/config_amd_linux @@ -138,14 +138,6 @@ "=== TODO ===", "Unit_Device_tgammaf_Accuracy_Limited_Positive", "=== TODO === fail on 100% test data", - "Unit_Device_hexp10_Accuracy_Positive", - "Unit_Device_h2exp10_Accuracy_Positive", - "Unit_Device_hexp2_Accuracy_Positive", - "Unit_Device_h2exp2_Accuracy_Positive", - "Unit_Device_hlog_Accuracy_Positive", - "Unit_Device_h2log_Accuracy_Positive", - "Unit_Device_hlog10_Accuracy_Positive", - "Unit_Device_h2log10_Accuracy_Positive", "Unit_Device___hfma2_Accuracy_Positive", #endif #if defined gfx90a || defined gfx942 || defined gfx950 diff --git a/projects/hip-tests/catch/unit/math/half_precision_math.cc b/projects/hip-tests/catch/unit/math/half_precision_math.cc index 4cfa766ffd..f599b59133 100644 --- a/projects/hip-tests/catch/unit/math/half_precision_math.cc +++ b/projects/hip-tests/catch/unit/math/half_precision_math.cc @@ -45,7 +45,7 @@ MATH_UNARY_HP_KERNEL_DEF(hcos); * - HIP_VERSION >= 5.2 */ MATH_UNARY_HP_TEST_DEF_IMPL(hcos, static_cast(std::cos), - ULPValidatorBuilderFactory(2)); + ULPValidatorBuilderFactory(1)); MATH_UNARY_HP_KERNEL_DEF(h2cos); @@ -63,7 +63,7 @@ MATH_UNARY_HP_KERNEL_DEF(h2cos); * - HIP_VERSION >= 5.2 */ MATH_UNARY_HP_TEST_DEF_IMPL(h2cos, static_cast(std::cos), - ULPValidatorBuilderFactory(2)); + ULPValidatorBuilderFactory(1)); MATH_UNARY_HP_KERNEL_DEF(hsin); @@ -82,7 +82,7 @@ MATH_UNARY_HP_KERNEL_DEF(hsin); * - HIP_VERSION >= 5.2 */ MATH_UNARY_HP_TEST_DEF_IMPL(hsin, static_cast(std::sin), - ULPValidatorBuilderFactory(2)); + ULPValidatorBuilderFactory(1)); MATH_UNARY_HP_KERNEL_DEF(h2sin); @@ -100,7 +100,7 @@ MATH_UNARY_HP_KERNEL_DEF(h2sin); * - HIP_VERSION >= 5.2 */ MATH_UNARY_HP_TEST_DEF_IMPL(h2sin, static_cast(std::sin), - ULPValidatorBuilderFactory(2)); + ULPValidatorBuilderFactory(1)); MATH_UNARY_HP_KERNEL_DEF(hexp); @@ -119,7 +119,7 @@ MATH_UNARY_HP_KERNEL_DEF(hexp); * - HIP_VERSION >= 5.2 */ MATH_UNARY_HP_TEST_DEF_IMPL(hexp, static_cast(std::exp), - ULPValidatorBuilderFactory(2)); + ULPValidatorBuilderFactory(1)); MATH_UNARY_HP_KERNEL_DEF(h2exp); @@ -137,7 +137,7 @@ MATH_UNARY_HP_KERNEL_DEF(h2exp); * - HIP_VERSION >= 5.2 */ MATH_UNARY_HP_TEST_DEF_IMPL(h2exp, static_cast(std::exp), - ULPValidatorBuilderFactory(2)); + ULPValidatorBuilderFactory(1)); MATH_UNARY_HP_KERNEL_DEF(hexp10); @@ -156,7 +156,7 @@ MATH_UNARY_HP_KERNEL_DEF(hexp10); * - HIP_VERSION >= 5.2 */ MATH_UNARY_HP_TEST_DEF_IMPL(hexp10, static_cast(exp10f), - ULPValidatorBuilderFactory(2)); + ULPValidatorBuilderFactory(1)); MATH_UNARY_HP_KERNEL_DEF(h2exp10); @@ -174,7 +174,7 @@ MATH_UNARY_HP_KERNEL_DEF(h2exp10); * - HIP_VERSION >= 5.2 */ MATH_UNARY_HP_TEST_DEF_IMPL(h2exp10, static_cast(exp10f), - ULPValidatorBuilderFactory(2)); + ULPValidatorBuilderFactory(1)); MATH_UNARY_HP_KERNEL_DEF(hexp2); @@ -193,7 +193,7 @@ MATH_UNARY_HP_KERNEL_DEF(hexp2); * - HIP_VERSION >= 5.2 */ MATH_UNARY_HP_TEST_DEF_IMPL(hexp2, static_cast(std::exp2), - ULPValidatorBuilderFactory(2)); + ULPValidatorBuilderFactory(1)); MATH_UNARY_HP_KERNEL_DEF(h2exp2); @@ -211,7 +211,7 @@ MATH_UNARY_HP_KERNEL_DEF(h2exp2); * - HIP_VERSION >= 5.2 */ MATH_UNARY_HP_TEST_DEF_IMPL(h2exp2, static_cast(std::exp2), - ULPValidatorBuilderFactory(2)); + ULPValidatorBuilderFactory(1)); MATH_UNARY_HP_KERNEL_DEF(hlog); @@ -230,7 +230,7 @@ MATH_UNARY_HP_KERNEL_DEF(hlog); * - HIP_VERSION >= 5.2 */ MATH_UNARY_HP_TEST_DEF_IMPL(hlog, static_cast(std::log), - ULPValidatorBuilderFactory(1)); + ULPValidatorBuilderFactory(1)); MATH_UNARY_HP_KERNEL_DEF(h2log); @@ -248,7 +248,7 @@ MATH_UNARY_HP_KERNEL_DEF(h2log); * - HIP_VERSION >= 5.2 */ MATH_UNARY_HP_TEST_DEF_IMPL(h2log, static_cast(std::log), - ULPValidatorBuilderFactory(1)); + ULPValidatorBuilderFactory(1)); MATH_UNARY_HP_KERNEL_DEF(hlog10); @@ -267,7 +267,7 @@ MATH_UNARY_HP_KERNEL_DEF(hlog10); * - HIP_VERSION >= 5.2 */ MATH_UNARY_HP_TEST_DEF_IMPL(hlog10, static_cast(std::log10), - ULPValidatorBuilderFactory(2)); + ULPValidatorBuilderFactory(1)); MATH_UNARY_HP_KERNEL_DEF(h2log10); @@ -285,7 +285,7 @@ MATH_UNARY_HP_KERNEL_DEF(h2log10); * - HIP_VERSION >= 5.2 */ MATH_UNARY_HP_TEST_DEF_IMPL(h2log10, static_cast(std::log10), - ULPValidatorBuilderFactory(2)); + ULPValidatorBuilderFactory(1)); MATH_UNARY_HP_KERNEL_DEF(hlog2); @@ -304,7 +304,7 @@ MATH_UNARY_HP_KERNEL_DEF(hlog2); * - HIP_VERSION >= 5.2 */ MATH_UNARY_HP_TEST_DEF_IMPL(hlog2, static_cast(std::log2), - ULPValidatorBuilderFactory(1)); + ULPValidatorBuilderFactory(1)); MATH_UNARY_HP_KERNEL_DEF(h2log2); @@ -322,7 +322,7 @@ MATH_UNARY_HP_KERNEL_DEF(h2log2); * - HIP_VERSION >= 5.2 */ MATH_UNARY_HP_TEST_DEF_IMPL(h2log2, static_cast(std::log2), - ULPValidatorBuilderFactory(1)); + ULPValidatorBuilderFactory(1)); MATH_UNARY_HP_KERNEL_DEF(hsqrt); @@ -341,7 +341,7 @@ MATH_UNARY_HP_KERNEL_DEF(hsqrt); * - HIP_VERSION >= 5.2 */ MATH_UNARY_HP_TEST_DEF_IMPL(hsqrt, static_cast(std::sqrt), - ULPValidatorBuilderFactory(1)); + ULPValidatorBuilderFactory(1)); MATH_UNARY_HP_KERNEL_DEF(h2sqrt); @@ -359,7 +359,7 @@ MATH_UNARY_HP_KERNEL_DEF(h2sqrt); * - HIP_VERSION >= 5.2 */ MATH_UNARY_HP_TEST_DEF_IMPL(h2sqrt, static_cast(std::sqrt), - ULPValidatorBuilderFactory(1)); + ULPValidatorBuilderFactory(1)); MATH_UNARY_HP_KERNEL_DEF(hceil); diff --git a/projects/hip-tests/catch/unit/math/math_common.hh b/projects/hip-tests/catch/unit/math/math_common.hh index 08bd720816..a92685210f 100644 --- a/projects/hip-tests/catch/unit/math/math_common.hh +++ b/projects/hip-tests/catch/unit/math/math_common.hh @@ -187,7 +187,9 @@ template class MathTest { std::stringstream ss; ss << "Input value(s): " << std::scientific << std::setprecision(std::numeric_limits::max_digits10 - 1); - ((ss << " " << args), ...) << "\n" << actual_val << " "; + ((ss << " " << args), ...) << "\n" + << "Output value: " << actual_val << "\n" + << "Condition failed: "; return ss.str(); } diff --git a/projects/hip-tests/catch/unit/math/validators.hh b/projects/hip-tests/catch/unit/math/validators.hh index 67c49132d4..d62ec5381b 100644 --- a/projects/hip-tests/catch/unit/math/validators.hh +++ b/projects/hip-tests/catch/unit/math/validators.hh @@ -25,6 +25,12 @@ THE SOFTWARE. #include #include +#include +#include +#include + +#include "Float16.hh" + // Define a new MatcherBase class with a public 'describe' member function because // Catch::MatcherBase::describe is protected and thus can't be used via a pointer to // Catch::MatcherBase. @@ -61,6 +67,113 @@ template class ValidatorBase : public MatcherBase bool nan = false; }; +struct Float16WithinUlpsMatcher : MatcherBase { + Float16WithinUlpsMatcher(Float16 target, uint64_t ulps) : m_target(target), m_ulps(ulps) {} + + bool match(Float16 const& matchee) const override { + // Comparison with NaN should always be false. + // This way we can rule it out before getting into the ugly details + if (__hisnan(matchee) || __hisnan(m_target)) { + return false; + } + + auto value_bits = convertFloat16toInt16(matchee); + auto target_bits = convertFloat16toInt16(m_target); + + // If signs differ, handle the special +0 vs -0 case explicitly. + if ((value_bits < 0) != (target_bits < 0)) { + return matchee == m_target; + } + + auto ulp_diff = std::abs(value_bits - target_bits); + return static_cast(ulp_diff) <= m_ulps; + } + + std::string describe() const override { + std::stringstream ret; + + ret << "is within " << m_ulps << " ULPs of "; + + write(ret, m_target); + ret << 'f'; + ret << " (["; + + write(ret, step(m_target, -FLOAT16_MAX, m_ulps)); + ret << ", "; + write(ret, step(m_target, FLOAT16_MAX, m_ulps)); + + ret << "])"; + + return ret.str(); + } + + private: + Float16 getNextAfter(Float16 from, Float16 direction) const { + constexpr int16_t signbit_float16 = 0x8000; + + // Encode inputs as 16-bit integers + const int16_t from_bits = convertFloat16toInt16(from); + const int16_t direction_bits = convertFloat16toInt16(direction); + + // Special cases + if (from_bits == direction_bits) return direction_bits; + if (std::abs(from_bits) == static_cast(0) && + std::abs(direction_bits) == static_cast(0)) + return direction; + + // Makes integer comparisons reflect numeric ordering across sign. + const int16_t from_ordered = (from_bits < 0) ? signbit_float16 - from_bits : from_bits; + const int16_t direction_ordered = + (direction_bits < 0) ? signbit_float16 - direction_bits : direction_bits; + + // Decide whether to move up or down by one ULP + const int16_t step = (from_ordered < direction_ordered) ? 1 : -1; + + // Take one step + const int16_t after_step_ordered = from_ordered + step; + + // Map back from ordered space to raw Float16 bits. + int16_t next_bits = + (after_step_ordered < 0) ? signbit_float16 - after_step_ordered : after_step_ordered; + + // Handle boundary behavior for the most-negative edge case. + if (from_ordered == -1 && (from_ordered < direction_ordered)) { + next_bits = signbit_float16; + } + + return convertInt16toFloat16(next_bits); + } + + Float16 step(Float16 start, Float16 direction, uint64_t steps) const { + Float16 result = start; + for (uint64_t i = 0; i < steps; ++i) { + result = getNextAfter(result, direction); + } + return result; + } + + void write(std::ostream& out, Float16 num) const { + const uint32_t float16_max_digits = 5; + out << std::scientific << std::setprecision(float16_max_digits) << num; + } + + static Float16 convertInt16toFloat16(int16_t d) { + Float16 i; + std::memcpy(&i, &d, sizeof(int16_t)); + return i; + } + + static int16_t convertFloat16toInt16(Float16 d) { + uint16_t i; + std::memcpy(&i, &d, sizeof(Float16)); + return i; + } + + Float16 m_target; + uint64_t m_ulps; +}; + + template auto ULPValidatorBuilderFactory(int64_t ulps) { return [=](T target, auto&&...) { return std::make_unique>( @@ -68,6 +181,13 @@ template auto ULPValidatorBuilderFactory(int64_t ulps) { }; }; +template <> inline auto ULPValidatorBuilderFactory(int64_t ulps) { + return [=](Float16 target, auto&&...) { + return std::make_unique>( + target, Float16WithinUlpsMatcher(target, ulps)); + }; +}; + template auto AbsValidatorBuilderFactory(double margin) { return [=](T target, auto&&...) { return std::make_unique>( @@ -96,7 +216,7 @@ template class EqValidator : public MatcherBase { std::string describe() const override { std::stringstream ss; - ss << " is not equal to " << target_; + ss << "is equal to " << target_; return ss.str(); }