diff --git a/modules/core/perf/perf_cvround.cpp b/modules/core/perf/perf_cvround.cpp index 933792dcaa..0e3ceb0597 100644 --- a/modules/core/perf/perf_cvround.cpp +++ b/modules/core/perf/perf_cvround.cpp @@ -4,42 +4,52 @@ namespace opencv_test { using namespace perf; -template -static void CvRoundMat(const cv::Mat & src, cv::Mat & dst) -{ - for (int y = 0; y < dst.rows; ++y) - { - const T * sptr = src.ptr(y); - int * dptr = dst.ptr(y); - - for (int x = 0; x < dst.cols; ++x) - dptr[x] = cvRound(sptr[x]); +#define DECL_ROUND_TEST(NAME, OP, EXTRA) \ + template \ + static void OP ## Mat(const cv::Mat & src, cv::Mat & dst) \ + { \ + for (int y = 0; y < dst.rows; ++y) \ + { \ + const T * sptr = src.ptr(y); \ + int * dptr = dst.ptr(y); \ + \ + for (int x = 0; x < dst.cols; ++x) \ + dptr[x] = OP(sptr[x]) EXTRA; \ + } \ + } \ + \ + PERF_TEST_P(Size_MatType, CvRound_Float ## NAME, \ + testing::Combine(testing::Values(TYPICAL_MAT_SIZES), \ + testing::Values(CV_32FC1, CV_64FC1))) \ + { \ + Size size = get<0>(GetParam()); \ + int type = get<1>(GetParam()), depth = CV_MAT_DEPTH(type); \ + \ + cv::Mat src(size, type), dst(size, CV_32SC1); \ + \ + declare.in(src, WARMUP_RNG).out(dst); \ + \ + if (depth == CV_32F) \ + { \ + TEST_CYCLE() \ + OP ## Mat(src, dst); \ + } \ + else if (depth == CV_64F) \ + { \ + TEST_CYCLE() \ + OP ## Mat(src, dst); \ + } \ + \ + SANITY_CHECK_NOTHING(); \ } -} - -PERF_TEST_P(Size_MatType, CvRound_Float, - testing::Combine(testing::Values(TYPICAL_MAT_SIZES), - testing::Values(CV_32FC1, CV_64FC1))) -{ - Size size = get<0>(GetParam()); - int type = get<1>(GetParam()), depth = CV_MAT_DEPTH(type); - cv::Mat src(size, type), dst(size, CV_32SC1); - - declare.in(src, WARMUP_RNG).out(dst); - - if (depth == CV_32F) - { - TEST_CYCLE() - CvRoundMat(src, dst); - } - else if (depth == CV_64F) - { - TEST_CYCLE() - CvRoundMat(src, dst); - } +DECL_ROUND_TEST(,cvRound,) +DECL_ROUND_TEST(_Ceil,cvCeil,) +DECL_ROUND_TEST(_Floor,cvFloor,) - SANITY_CHECK_NOTHING(); -} +/* For FP classification tests, try to test them in way which uses + branching logic and avoids extra FP logic. */ +DECL_ROUND_TEST(_NaN,cvIsNaN, ? 1 : 2) +DECL_ROUND_TEST(_Inf,cvIsInf, ? 1 : 2) } // namespace diff --git a/modules/core/test/test_math.cpp b/modules/core/test/test_math.cpp index d65b3fa39e..8b13a391cb 100644 --- a/modules/core/test/test_math.cpp +++ b/modules/core/test/test_math.cpp @@ -3923,5 +3923,59 @@ TEST(Core_SoftFloat, CvRound) } } +template +static void checkRounding(T in, int outCeil, int outFloor) +{ + EXPECT_EQ(outCeil,cvCeil(in)); + EXPECT_EQ(outFloor,cvFloor(in)); + + /* cvRound is not expected to be IEEE compliant. The implementation + should round to one of the above. */ + EXPECT_TRUE((cvRound(in) == outCeil) || (cvRound(in) == outFloor)); +} + +TEST(Core_FastMath, InlineRoundingOps) +{ + struct + { + double in; + int outCeil; + int outFloor; + } values[] = + { + // Values are chosen to convert to binary float 32/64 exactly + { 1.0, 1, 1 }, + { 1.5, 2, 1 }, + { -1.5, -1, -2} + }; + + for (int i = 0, maxi = sizeof(values) / sizeof(values[0]); i < maxi; i++) + { + checkRounding(values[i].in, values[i].outCeil, values[i].outFloor); + checkRounding((float)values[i].in, values[i].outCeil, values[i].outFloor); + } +} + +TEST(Core_FastMath, InlineNaN) +{ + EXPECT_EQ( cvIsNaN((float) NAN), 1); + EXPECT_EQ( cvIsNaN((float) -NAN), 1); + EXPECT_EQ( cvIsNaN(0.0f), 0); + EXPECT_EQ( cvIsNaN((double) NAN), 1); + EXPECT_EQ( cvIsNaN((double) -NAN), 1); + EXPECT_EQ( cvIsNaN(0.0), 0); +} + +TEST(Core_FastMath, InlineIsInf) +{ + // Assume HUGE_VAL is infinity. Strictly speaking, may not always be true. + EXPECT_EQ( cvIsInf((float) HUGE_VAL), 1); + EXPECT_EQ( cvIsInf((float) -HUGE_VAL), 1); + EXPECT_EQ( cvIsInf(0.0f), 0); + EXPECT_EQ( cvIsInf((double) HUGE_VAL), 1); + EXPECT_EQ( cvIsInf((double) -HUGE_VAL), 1); + EXPECT_EQ( cvIsInf(0.0), 0); +} + }} // namespace /* End of file. */