[IE Common][Tests] saturated_cast: refactoring & tests (#1304)
* [IE Common] Refactor saturated_cast * [IE Common][Tests] Add tests for saturated casts * [IE Common] Review fixes * [IE Common] Make enable_if check a template parameter
This commit is contained in:
parent
8fe1ef0b41
commit
382b442ab3
@ -1330,28 +1330,13 @@ bool UnrollRNN_if(TensorIterator::Body& net, const std::function<bool(const RNNC
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename TO, typename FROM>
|
||||
bool isConversionNarrowing(FROM from) {
|
||||
return from == (static_cast<FROM>(static_cast<TO>(from)));
|
||||
}
|
||||
|
||||
template <typename TO, typename FROM>
|
||||
TO saturatedCast(FROM from) {
|
||||
FROM max = isConversionNarrowing<FROM>(std::numeric_limits<TO>::max()) ? std::numeric_limits<FROM>::max() :
|
||||
static_cast<FROM>(std::numeric_limits<TO>::max());
|
||||
FROM min = isConversionNarrowing<FROM>(std::numeric_limits<TO>::min()) ? std::numeric_limits<FROM>::min() :
|
||||
static_cast<FROM>(std::numeric_limits<TO>::min());
|
||||
|
||||
return static_cast<TO>(std::min(std::max(from, min), max));
|
||||
}
|
||||
|
||||
template <Precision::ePrecision PREC_FROM, Precision::ePrecision PREC_TO>
|
||||
void convertArrayPrecision(typename PrecisionTrait<PREC_TO>::value_type* dst,
|
||||
const typename PrecisionTrait<PREC_FROM>::value_type* src, size_t nelem) {
|
||||
using dst_type = typename PrecisionTrait<PREC_TO>::value_type;
|
||||
|
||||
for (size_t i = 0; i < nelem; i++) {
|
||||
dst[i] = saturatedCast<dst_type>(src[i]);
|
||||
dst[i] = PrecisionUtils::saturate_cast<dst_type>(src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,9 @@
|
||||
#include <ie_api.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
|
||||
/**
|
||||
* @brief Inference Engine Plugin API namespace
|
||||
@ -123,6 +126,67 @@ f16tof32Arrays(float* dst, const ie_fp16* src, size_t nelem, float scale = 1.f,
|
||||
INFERENCE_ENGINE_API_CPP(void)
|
||||
f32tof16Arrays(ie_fp16* dst, const float* src, size_t nelem, float scale = 1.f, float bias = 0.f);
|
||||
|
||||
/**
|
||||
* @brief Converts one integral type to another saturating the result if the source value doesn't fit
|
||||
* into destination type range
|
||||
* @ingroup ie_dev_api_precision
|
||||
*
|
||||
* @param value Value to be converted
|
||||
*/
|
||||
template <class OutT, class InT, typename std::enable_if<
|
||||
std::is_integral<OutT>::value && std::is_integral<InT>::value &&
|
||||
std::is_signed<InT>::value &&
|
||||
!std::is_same<OutT, InT>::value
|
||||
>::type* = nullptr>
|
||||
inline OutT saturate_cast(const InT& value) {
|
||||
if (std::numeric_limits<OutT>::max() > std::numeric_limits<InT>::max() &&
|
||||
std::numeric_limits<OutT>::min() < std::numeric_limits<InT>::min()) {
|
||||
return static_cast<OutT>(value);
|
||||
}
|
||||
|
||||
const InT max = std::numeric_limits<OutT>::max() < std::numeric_limits<InT>::max() ? std::numeric_limits<OutT>::max() :
|
||||
std::numeric_limits<InT>::max();
|
||||
const InT min = std::numeric_limits<OutT>::min() > std::numeric_limits<InT>::min() ? std::numeric_limits<OutT>::min() :
|
||||
std::numeric_limits<InT>::min();
|
||||
|
||||
return std::min(std::max(value, min), max);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Converts one integral type to another saturating the result if the source value doesn't fit
|
||||
* into destination type range
|
||||
* @ingroup ie_dev_api_precision
|
||||
*
|
||||
* @param value Value to be converted
|
||||
*/
|
||||
template <class OutT, class InT, typename std::enable_if<
|
||||
std::is_integral<OutT>::value && std::is_integral<InT>::value &&
|
||||
std::is_unsigned<InT>::value &&
|
||||
!std::is_same<OutT, InT>::value
|
||||
>::type* = nullptr>
|
||||
inline OutT saturate_cast(const InT& value) {
|
||||
if (std::numeric_limits<OutT>::max() > std::numeric_limits<InT>::max()) {
|
||||
return static_cast<OutT>(value);
|
||||
}
|
||||
|
||||
const InT max = std::numeric_limits<OutT>::max() < std::numeric_limits<InT>::max() ? std::numeric_limits<OutT>::max() :
|
||||
std::numeric_limits<InT>::max();
|
||||
|
||||
return std::min(value, max);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Converts one integral type to another saturating the result if the source value doesn't fit
|
||||
* into destination type range
|
||||
* @ingroup ie_dev_api_precision
|
||||
*
|
||||
* @param value Value to be converted
|
||||
*/
|
||||
template <class InT>
|
||||
inline InT saturate_cast(const InT& value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
} // namespace PrecisionUtils
|
||||
|
||||
} // namespace InferenceEngine
|
||||
|
@ -4,11 +4,20 @@
|
||||
|
||||
set(TARGET_NAME ieUnitTests)
|
||||
|
||||
# Find OpenCV components if exist
|
||||
find_package(OpenCV COMPONENTS imgcodecs videoio imgproc QUIET)
|
||||
if(NOT OpenCV_FOUND)
|
||||
message(ERROR "OPENCV is disabled or not found, " ${TARGET_NAME} " needs OpenCV for its build")
|
||||
else()
|
||||
add_definitions(-DUSE_OPENCV)
|
||||
endif()
|
||||
|
||||
addIeTargetTest(
|
||||
NAME ${TARGET_NAME}
|
||||
ROOT ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
LINK_LIBRARIES
|
||||
unitTestUtils
|
||||
${OpenCV_LIBRARIES}
|
||||
ADD_CPPLINT
|
||||
DEPENDENCIES
|
||||
mock_engine
|
||||
|
@ -0,0 +1,114 @@
|
||||
// Copyright (C) 2020 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "common_test_utils/test_common.hpp"
|
||||
|
||||
#include "precision_utils.h"
|
||||
#include "ie_precision.hpp"
|
||||
|
||||
#include <opencv2/core.hpp>
|
||||
|
||||
using namespace InferenceEngine;
|
||||
|
||||
class SaturateCastTestsI64ToI32 : public CommonTestUtils::TestsCommon {
|
||||
public:
|
||||
using fromType = typename PrecisionTrait<Precision::I64>::value_type;
|
||||
using toType = typename PrecisionTrait<Precision::I32>::value_type;
|
||||
};
|
||||
|
||||
TEST_F(SaturateCastTestsI64ToI32, I64ToI32NonNarrowingPositive) {
|
||||
const auto value = fromType{42};
|
||||
EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
|
||||
}
|
||||
|
||||
TEST_F(SaturateCastTestsI64ToI32, I64ToI32NonNarrowingNegative) {
|
||||
const auto value = fromType{-42};
|
||||
EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
|
||||
}
|
||||
|
||||
TEST_F(SaturateCastTestsI64ToI32, I64ToI32NarrowingMaxToMax) {
|
||||
const auto value = std::numeric_limits<fromType>::max();
|
||||
EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
|
||||
}
|
||||
|
||||
TEST_F(SaturateCastTestsI64ToI32, I64ToI32NarrowingNonMaxToMax) {
|
||||
const auto value = std::numeric_limits<fromType>::max() - 1;
|
||||
EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
|
||||
}
|
||||
|
||||
TEST_F(SaturateCastTestsI64ToI32, I64ToI32NarrowingMinToMin) {
|
||||
const auto value = std::numeric_limits<fromType>::min();
|
||||
EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
|
||||
}
|
||||
|
||||
TEST_F(SaturateCastTestsI64ToI32, I64ToI32NarrowingNonMinToMin) {
|
||||
const auto value = std::numeric_limits<fromType>::min() + 1;
|
||||
EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
|
||||
}
|
||||
|
||||
class SaturateCastTestsU64ToI32 : public CommonTestUtils::TestsCommon {
|
||||
public:
|
||||
using fromType = typename PrecisionTrait<Precision::U64>::value_type;
|
||||
using toType = typename PrecisionTrait<Precision::I32>::value_type;
|
||||
};
|
||||
|
||||
TEST_F(SaturateCastTestsU64ToI32, U64ToI32NonNarrowing) {
|
||||
const auto value = fromType{42};
|
||||
EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
|
||||
}
|
||||
|
||||
TEST_F(SaturateCastTestsU64ToI32, U64ToI32NarrowingMaxToMax) {
|
||||
const auto value = std::numeric_limits<fromType>::max();
|
||||
EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
|
||||
}
|
||||
|
||||
TEST_F(SaturateCastTestsU64ToI32, U64ToI32NarrowingNonMaxToMax) {
|
||||
const auto value = std::numeric_limits<fromType>::max() - 1;
|
||||
EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
|
||||
}
|
||||
|
||||
class SaturateCastTestsBoolToU8 : public CommonTestUtils::TestsCommon {
|
||||
public:
|
||||
using fromType = typename PrecisionTrait<Precision::BOOL>::value_type;
|
||||
using toType = typename PrecisionTrait<Precision::U8>::value_type;
|
||||
};
|
||||
|
||||
TEST_F(SaturateCastTestsBoolToU8, BOOLtoU8MaxToNonMax) {
|
||||
const auto value = std::numeric_limits<fromType>::max();
|
||||
EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
|
||||
}
|
||||
|
||||
class SaturateCastTestsBoolToI32 : public CommonTestUtils::TestsCommon {
|
||||
public:
|
||||
using fromType = typename PrecisionTrait<Precision::BOOL>::value_type;
|
||||
using toType = typename PrecisionTrait<Precision::I32>::value_type;
|
||||
};
|
||||
|
||||
TEST_F(SaturateCastTestsBoolToI32, BOOLtoI32MaxToNonMax) {
|
||||
const auto value = std::numeric_limits<fromType>::max();
|
||||
EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
|
||||
}
|
||||
|
||||
class SaturateCastTestsU8ToI32 : public CommonTestUtils::TestsCommon {
|
||||
public:
|
||||
using fromType = typename PrecisionTrait<Precision::U8>::value_type;
|
||||
using toType = typename PrecisionTrait<Precision::I32>::value_type;
|
||||
};
|
||||
|
||||
TEST_F(SaturateCastTestsU8ToI32, U8toI32FMaxToNonMax) {
|
||||
const auto value = std::numeric_limits<fromType>::max();
|
||||
EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
|
||||
}
|
||||
|
||||
class SaturateCastTestsU16ToI32 : public CommonTestUtils::TestsCommon {
|
||||
public:
|
||||
using fromType = typename PrecisionTrait<Precision::U8>::value_type;
|
||||
using toType = typename PrecisionTrait<Precision::I32>::value_type;
|
||||
};
|
||||
|
||||
TEST_F(SaturateCastTestsU16ToI32, U16toI32FMaxToNonMax) {
|
||||
const auto value = std::numeric_limits<fromType>::max();
|
||||
EXPECT_EQ(PrecisionUtils::saturate_cast<toType>(value), cv::saturate_cast<toType>(value));
|
||||
}
|
Loading…
Reference in New Issue
Block a user