diff options
Diffstat (limited to 'reference_model/src/verify/verify_utils.cc')
-rw-r--r-- | reference_model/src/verify/verify_utils.cc | 96 |
1 files changed, 95 insertions, 1 deletions
diff --git a/reference_model/src/verify/verify_utils.cc b/reference_model/src/verify/verify_utils.cc index 9b20fb2..414f7d7 100644 --- a/reference_model/src/verify/verify_utils.cc +++ b/reference_model/src/verify/verify_utils.cc @@ -48,8 +48,9 @@ NLOHMANN_JSON_SERIALIZE_ENUM(VerifyMode, { VerifyMode::Exact, "EXACT" }, { VerifyMode::Ulp, "ULP" }, { VerifyMode::DotProduct, "DOT_PRODUCT" }, - { VerifyMode::ReduceProduct, "REDUCE_PRODUCT" }, { VerifyMode::FpSpecial, "FP_SPECIAL" }, + { VerifyMode::ReduceProduct, "REDUCE_PRODUCT" }, + { VerifyMode::AbsError, "ABS_ERROR" }, }) void from_json(const nlohmann::json& j, UlpInfo& ulpInfo) @@ -189,4 +190,97 @@ int32_t ilog2(double v) } return n; } + +static_assert(std::numeric_limits<float>::is_iec559, + "TOSA Reference Model has not been built with standard IEEE 754 32-bit float support; Bounds based " + "verification is invalid"); +static_assert(std::numeric_limits<double>::is_iec559, + "TOSA Reference Model has not been built with standard IEEE 754 64-bit float support; Bounds based " + "verification is invalid"); + +bool tosaCheckFloatBound(float testValue, double referenceValue, double errorBound) +{ + // Both must be NaNs to be correct + if (std::isnan(referenceValue) || std::isnan(testValue)) + { + if (std::isnan(referenceValue) && std::isnan(testValue)) + { + return true; + } + WARNING("[Verifier][Bound] Non-matching NaN values - ref (%10f) versus test (%10f).", referenceValue, + testValue); + return false; + } + + // Make the sign of the reference value positive + // and adjust the test value appropriately. + if (referenceValue < 0) + { + referenceValue = -referenceValue; + testValue = -testValue; + } + if (errorBound < 0) + { + errorBound = -errorBound; + } + + // At this point we are ready to calculate the ULP bounds for the reference value. + double referenceMin, referenceMax; + + // If the reference is infinity e.g. the result of an overflow the test value must + // be infinity of an appropriate sign. + if (std::isinf(referenceValue)) + { + // We already canonicalized the input such that the reference value is positive + // so no need to check again here. + referenceMin = std::numeric_limits<float>::infinity(); + referenceMax = std::numeric_limits<float>::infinity(); + } + else if (referenceValue == 0) + { + // For zero we require that the results match exactly with the correct sign. + referenceMin = 0; + referenceMax = 0; + } + else + { + + // Scale by the number of ULPs requested by the user. + referenceMax = referenceValue + errorBound; + referenceMin = referenceValue - errorBound; + + // Handle the overflow cases. + if (referenceMax > AccPrecision<float>::normal_max) + { + referenceMax = std::numeric_limits<float>::infinity(); + } + + if (referenceMin > AccPrecision<float>::normal_max) + { + referenceMin = std::numeric_limits<float>::infinity(); + } + + // And the underflow cases. + if (referenceMax < AccPrecision<float>::normal_min) + { + referenceMax = AccPrecision<float>::normal_min; + } + + if (referenceMin < AccPrecision<float>::normal_min) + { + referenceMin = 0.0; + } + } + + // And finally... Do the comparison. + double testValue64 = static_cast<double>(testValue); + bool withinBound = testValue64 >= referenceMin && testValue64 <= referenceMax; + if (!withinBound) + { + WARNING( + "[Verifier][Bound] value (%10.10f) is not in error bound %g range (%10.10f <= ref (%10.10f) <= %10.10f).", + testValue64, errorBound, referenceMin, referenceValue, referenceMax); + } + return withinBound; +} } // namespace TosaReference |