diff --git a/modules/core/include/opencv2/core/cvdef.h b/modules/core/include/opencv2/core/cvdef.h index 5ce799bb20..96603e4ca5 100644 --- a/modules/core/include/opencv2/core/cvdef.h +++ b/modules/core/include/opencv2/core/cvdef.h @@ -947,7 +947,7 @@ public: { Cv32suf in; in.f = x; - w = (ushort)(in.u >> 16); + w = (ushort)((in.u + (((in.u & 0x7fffffff) <= 0x7f7f7fff) << 15)) >> 16); } operator float() const diff --git a/modules/core/include/opencv2/core/hal/intrin.hpp b/modules/core/include/opencv2/core/hal/intrin.hpp index 6e033bf67c..745a9dc40f 100644 --- a/modules/core/include/opencv2/core/hal/intrin.hpp +++ b/modules/core/include/opencv2/core/hal/intrin.hpp @@ -766,10 +766,11 @@ namespace CV__SIMD_NAMESPACE { inline void v_pack_store(const bfloat* ptr, const v_float32& v) { - v_int32 iv = v_shr<16>(v_reinterpret_as_s32(v)); - cv::v_pack_store((short*)ptr, iv); + v_int32 av = v_reinterpret_as_s32(v_abs(v)); + v_int32 iv = v_reinterpret_as_s32(v); + iv = v_add(iv, v_and(v_le(av, vx_setall_s32(0x7f7f7fff)), vx_setall_s32(0x8000))); + cv::v_pack_store((short*)ptr, v_shr<16>(iv)); } - #endif /** @brief SIMD processing state cleanup call */ diff --git a/modules/core/test/test_math.cpp b/modules/core/test/test_math.cpp index 616f0ec573..21d90ef14f 100644 --- a/modules/core/test/test_math.cpp +++ b/modules/core/test/test_math.cpp @@ -11,6 +11,7 @@ #include #include "opencv2/core/softfloat.hpp" #include "opencv2/core/core_c.h" +#include "opencv2/core/hal/intrin.hpp" namespace opencv_test { namespace { @@ -3354,5 +3355,97 @@ TEST(Core_FastMath, InlineIsInf) EXPECT_EQ( cvIsInf(suf.f), 0); } +TEST(Core_BFloat, CornerCases) +{ + float data[] = {0.f, -0.f, 1.f, -1.f, expf(1.f), FLT_MAX, -FLT_MAX, + std::numeric_limits::infinity(), + -std::numeric_limits::infinity(), + std::numeric_limits::quiet_NaN() + }; + size_t n0 = sizeof(data)/sizeof(data[0]); + for (size_t i = 0; i < n0; i++) { + float x = data[i]; + Cv32suf suf0, suf1; + suf0.f = x; + uint16_t x0 = (uint16_t)(suf0.u >> 16); + bfloat x1 = bfloat(x); + suf0.u = x0 << 16; + suf1.f = (float)x1; + //printf("%zu. orig = %f, restored (old) = %f, restored (new) = %f\n", i, x, suf0.f, suf1.f); + if (suf0.u != suf1.u) { + EXPECT_LE(fabs(suf1.f - x), fabs(suf0.f - x)); + } + } +} + +TEST(Core_BFloat, convert) +{ + size_t N = 1 << 20; + std::vector bigdata(N); + RNG& rng = theRNG(); + int m_max = 1 << 24; + double m_scale = 1./m_max; + for (size_t i = 0; i < N; i++) { + double m = (m_max + rng.uniform(0, m_max))*m_scale; + double e = pow(2., rng.uniform(-127, 127)); + double s = rng.uniform(0, 2)*2 - 1; + float x = (float)(s*m*e); + bigdata[i] = x; + } + + double sum0 = 0, sqsum0 = 0, maxerr0 = 0, maxerr1 = 0, sum1 = 0, sqsum1 = 0; + for (size_t i = 0; i < N; i++) { + float x = bigdata[i]; + Cv32suf suf0, suf1; + suf0.f = suf1.f = x; + uint16_t x0 = (uint16_t)(suf0.u >> 16); + bfloat x1 = bfloat(suf1.f); + suf0.u = x0 << 16; + suf1.f = (float)x1; + double err0 = fabs(x - suf0.f)/(fabs(x) + DBL_EPSILON); + double err1 = fabs(x - suf1.f)/(fabs(x) + DBL_EPSILON); + maxerr0 = std::max(maxerr0, err0); + maxerr1 = std::max(maxerr1, err1); + sum0 += err0; + sqsum0 += err0*err0; + sum1 += err1; + sqsum1 += err1*err1; + } + double mean0 = sum0/N; + double stddev0 = sqrt(std::max(sqsum0 - N*mean0*mean0, 0.)/(N-1)); + double mean1 = sum1/N; + double stddev1 = sqrt(std::max(sqsum1 - N*mean1*mean1, 0.)/(N-1)); + + //if (maxerr1 > maxerr0 || mean1 > mean0 || stddev1 > stddev0) + { + printf("maxerr0 = %g, mean0 = %g, stddev0 = %g\nmaxerr1 = %g, mean1 = %g, stddev1 = %g\n", + maxerr0, mean0, stddev0, maxerr1, mean1, stddev1); + } + + EXPECT_LE(maxerr1, maxerr0); + EXPECT_LE(mean1, mean0); + EXPECT_LE(stddev1, stddev0); + +#if CV_SIMD || CV_SIMD_SCALABLE + //printf("checking vector part ...\n"); + std::vector bfdata(N); + int vlanes = VTraits::vlanes(); + for (size_t i = 0; i < N; i += vlanes) + { + v_float32 x = v_load(&bigdata[i]); + v_pack_store(&bfdata[i], x); + } + + int vecerr = 0; + for (size_t i = 0; i < N; i++) { + Cv32suf suf0, suf1; + suf0.f = (float)bfloat(bigdata[i]); + suf1.f = (float)bfdata[i]; + vecerr += suf0.u != suf1.u; + } + EXPECT_EQ(0, vecerr); +#endif +} + }} // namespace /* End of file. */