diff options
author | Jeremy Johnson <jeremy.johnson@arm.com> | 2023-10-26 13:53:14 +0100 |
---|---|---|
committer | Eric Kunze <eric.kunze@arm.com> | 2023-11-02 23:22:09 +0000 |
commit | a4d907e8686791dd84ed987d0d79325c4d908b73 (patch) | |
tree | 9748ef39183b7548a9ff50d457920eace3a6fdec /reference_model/src/verify/verify_ulp.cc | |
parent | d1a08ce27ef8d0f6cf77e1b864610aade06edc5c (diff) | |
download | reference_model-a4d907e8686791dd84ed987d0d79325c4d908b73.tar.gz |
Main compliance testing support for MUL
Update verify ULP mode to allow fractions (e.g. 0.5).
Update pseudo generator to accept ranges.
Fix up pseudo random distribution based on ranges.
Change-Id: I9168c5f7d37722678c0f1f9e906953c8cec367b1
Signed-off-by: Jeremy Johnson <jeremy.johnson@arm.com>
Diffstat (limited to 'reference_model/src/verify/verify_ulp.cc')
-rw-r--r-- | reference_model/src/verify/verify_ulp.cc | 47 |
1 files changed, 23 insertions, 24 deletions
diff --git a/reference_model/src/verify/verify_ulp.cc b/reference_model/src/verify/verify_ulp.cc index 486c0ff..8c27191 100644 --- a/reference_model/src/verify/verify_ulp.cc +++ b/reference_model/src/verify/verify_ulp.cc @@ -31,7 +31,7 @@ static_assert(std::numeric_limits<double>::is_iec559, "TOSA Reference Model has not been built with standard IEE574 64-bit float support; ULP based " "verifcation is invalid"); -bool tosaCheckULP(float testValue, double referenceValue, int64_t ulpCount) +bool tosaCheckULP(double referenceValue, float testValue, double ulpNum) { // Start by sanitizing the input. @@ -71,57 +71,55 @@ bool tosaCheckULP(float testValue, double referenceValue, int64_t ulpCount) else { // Find the exponent of the reference value. - int referenceExponent; - std::frexp(referenceValue, &referenceExponent); + int32_t referenceExponent = ilog2(referenceValue); // Work out the values magnitude - by raising 2 to the power of the // exponent and taking the normalized minimum for denormal values - const double referencePower2 = - std::max(std::ldexp(1.0, referenceExponent), static_cast<double>(std::numeric_limits<float>::min())); + const double referencePower2 = std::max(exp2(referenceExponent), AccPrecision<float>::normal_min); // Get the value of changing the last bit - by shifting the least significant bit to this magnitude // i.e. the ULP. - double ulpValue = referencePower2 * std::ldexp(1.0, -23); - - // It is possible that within one ULP we cross a boundary where we need to change the exponent, - // if this happens we will take the ULP for the larger exponent. - if (referenceValue + ulpValue > 2 * referencePower2) - { - ulpValue = 2 * ulpValue; - } + double ulpValue = referencePower2 * exp2(-AccPrecision<float>::normal_frac); // Scale by the number of ULPs requested by the user. - referenceMax = referenceValue + ulpValue * ulpCount; - referenceMin = referenceValue - ulpValue * ulpCount; + referenceMax = referenceValue + ulpValue * ulpNum; + referenceMin = referenceValue - ulpValue * ulpNum; // Handle the overflow cases. - if (referenceMax > std::numeric_limits<float>::max()) + if (referenceMax > AccPrecision<float>::normal_max) { referenceMax = std::numeric_limits<float>::infinity(); } - if (referenceMin > std::numeric_limits<float>::max()) + if (referenceMin > AccPrecision<float>::normal_max) { referenceMin = std::numeric_limits<float>::infinity(); } // And the underflow cases. - if (referenceMax < std::numeric_limits<float>::min()) + if (referenceMax < AccPrecision<float>::normal_min) { - referenceMax = std::numeric_limits<float>::min(); + referenceMax = AccPrecision<float>::normal_min; } - if (referenceMin < std::numeric_limits<float>::min()) + if (referenceMin < AccPrecision<float>::normal_min) { - referenceMin = 0; + referenceMin = 0.0; } } // And finally... Do the comparison. - return static_cast<double>(testValue) >= referenceMin && static_cast<double>(testValue) <= referenceMax; + double testValue64 = static_cast<double>(testValue); + bool withinUlp = testValue64 >= referenceMin && testValue64 <= referenceMax; + if (!withinUlp) + { + WARNING("[Verfier][ULP] value (%10f) is not in ULP %g range (%10f <= ref (%10f) <= %10f).", testValue64, ulpNum, + referenceMin, referenceValue, referenceMax); + } + return withinUlp; } } // namespace -bool verifyULP(const CTensor* referenceTensor, const CTensor* implementationTensor, uint64_t ulp) +bool verifyULP(const CTensor* referenceTensor, const CTensor* implementationTensor, const UlpInfo& ulpInfo) { // Validate that tensors are provided TOSA_REF_REQUIRE(referenceTensor != nullptr, "[ULP] Reference tensor is missing"); @@ -132,10 +130,11 @@ bool verifyULP(const CTensor* referenceTensor, const CTensor* implementationTens numElements(std::vector<int32_t>(referenceTensor->shape, referenceTensor->shape + referenceTensor->num_dims)); TOSA_REF_REQUIRE(elementCount > 0, "[ULP] Invalid shape for reference tensor"); + const double ulp = ulpInfo.ulp; switch (implementationTensor->data_type) { case tosa_datatype_fp32_t: { - const auto* refData = reinterpret_cast<const float*>(referenceTensor->data); + const auto* refData = reinterpret_cast<const double*>(referenceTensor->data); TOSA_REF_REQUIRE(refData != nullptr, "[ULP] Missing data for reference"); const auto* impData = reinterpret_cast<const float*>(implementationTensor->data); TOSA_REF_REQUIRE(impData != nullptr, "[ULP] Missing data for implementation"); |