Skip to content

Commit e49febb

Browse files
committed
Merge pull request opencv#10269 from terfendail:softdouble_round
2 parents 7e680bd + 86b128d commit e49febb

File tree

3 files changed

+233
-1
lines changed

3 files changed

+233
-1
lines changed

modules/core/include/opencv2/core/softfloat.hpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,9 @@ CV_EXPORTS int cvTrunc(const cv::softdouble& a);
401401
CV_EXPORTS int cvRound(const cv::softfloat& a);
402402
CV_EXPORTS int cvRound(const cv::softdouble& a);
403403

404+
/** @brief Rounds a number to nearest even long long integer */
405+
CV_EXPORTS int64_t cvRound64(const cv::softdouble& a);
406+
404407
/** @brief Rounds a number down to integer */
405408
CV_EXPORTS int cvFloor(const cv::softfloat& a);
406409
CV_EXPORTS int cvFloor(const cv::softdouble& a);
@@ -430,12 +433,18 @@ template<> inline short saturate_cast<short>(softdouble a) { return (short)std::
430433
template<> inline int saturate_cast<int>(softfloat a) { return cvRound(a); }
431434
template<> inline int saturate_cast<int>(softdouble a) { return cvRound(a); }
432435

433-
/** @brief Saturate cast to unsigned integer
436+
template<> inline int64_t saturate_cast<int64_t>(softfloat a) { return cvRound(a); }
437+
template<> inline int64_t saturate_cast<int64_t>(softdouble a) { return cvRound64(a); }
438+
439+
/** @brief Saturate cast to unsigned integer and unsigned long long integer
434440
We intentionally do not clip negative numbers, to make -1 become 0xffffffff etc.
435441
*/
436442
template<> inline unsigned saturate_cast<unsigned>(softfloat a) { return cvRound(a); }
437443
template<> inline unsigned saturate_cast<unsigned>(softdouble a) { return cvRound(a); }
438444

445+
template<> inline uint64_t saturate_cast<uint64_t>(softfloat a) { return cvRound(a); }
446+
template<> inline uint64_t saturate_cast<uint64_t>(softdouble a) { return cvRound64(a); }
447+
439448
/** @brief Min and Max functions */
440449
inline softfloat min(const softfloat& a, const softfloat& b) { return (a > b) ? b : a; }
441450
inline softdouble min(const softdouble& a, const softdouble& b) { return (a > b) ? b : a; }

modules/core/src/softfloat.cpp

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ static bool f32_lt( float32_t, float32_t );
183183
| 64-bit (double-precision) floating-point operations.
184184
*----------------------------------------------------------------------------*/
185185
static int_fast32_t f64_to_i32( float64_t, uint_fast8_t, bool );
186+
static int_fast64_t f64_to_i64( float64_t, uint_fast8_t, bool );
186187
static int_fast32_t f64_to_i32_r_minMag( float64_t, bool );
187188
static float32_t f64_to_f32( float64_t );
188189
static float64_t f64_roundToInt( float64_t, uint_fast8_t, bool );
@@ -258,6 +259,8 @@ int cvRound(const cv::softdouble& a) { return cv::f64_to_i32(a, cv::round_near_e
258259
int cvFloor(const cv::softdouble& a) { return cv::f64_to_i32(a, cv::round_min, false); }
259260
int cvCeil (const cv::softdouble& a) { return cv::f64_to_i32(a, cv::round_max, false); }
260261

262+
int64_t cvRound64(const cv::softdouble& a) { return cv::f64_to_i64(a, cv::round_near_even, false); }
263+
261264
namespace cv
262265
{
263266
softdouble::operator softfloat() const { return f64_to_f32(*this); }
@@ -468,6 +471,7 @@ static float32_t softfloat_mulAddF32(uint_fast32_t, uint_fast32_t, uint_fast32_t
468471

469472
/*----------------------------------------------------------------------------
470473
*----------------------------------------------------------------------------*/
474+
static int_fast64_t softfloat_roundToI64( bool, uint_fast64_t, uint_fast64_t, uint_fast8_t, bool);
471475

472476
struct exp16_sig64 { int_fast16_t exp; uint_fast64_t sig; };
473477
static struct exp16_sig64 softfloat_normSubnormalF64Sig( uint_fast64_t );
@@ -2026,6 +2030,59 @@ static int_fast32_t f64_to_i32( float64_t a, uint_fast8_t roundingMode, bool exa
20262030
return softfloat_roundToI32( sign, sig, roundingMode, exact );
20272031
}
20282032

2033+
static int_fast64_t f64_to_i64(float64_t a, uint_fast8_t roundingMode, bool exact )
2034+
{
2035+
uint_fast64_t uiA;
2036+
bool sign;
2037+
int_fast16_t exp;
2038+
uint_fast64_t sig;
2039+
int_fast16_t shiftDist;
2040+
2041+
/*------------------------------------------------------------------------
2042+
*------------------------------------------------------------------------*/
2043+
uiA = a.v;
2044+
sign = signF64UI(uiA);
2045+
exp = expF64UI(uiA);
2046+
sig = fracF64UI(uiA);
2047+
/*------------------------------------------------------------------------
2048+
*------------------------------------------------------------------------*/
2049+
#if (i64_fromNaN != i64_fromPosOverflow) || (i64_fromNaN != i64_fromNegOverflow)
2050+
if ((exp == 0x7FF) && sig) {
2051+
#if (i64_fromNaN == i64_fromPosOverflow)
2052+
sign = 0;
2053+
#elif (i64_fromNaN == i64_fromNegOverflow)
2054+
sign = 1;
2055+
#else
2056+
raiseFlags(flag_invalid);
2057+
return i64_fromNaN;
2058+
#endif
2059+
}
2060+
#endif
2061+
/*------------------------------------------------------------------------
2062+
*------------------------------------------------------------------------*/
2063+
if (exp) sig |= UINT64_C(0x0010000000000000);
2064+
shiftDist = 0x433 - exp;
2065+
if (shiftDist <= 0) {
2066+
uint_fast64_t z = sig << -shiftDist;
2067+
if ((shiftDist < -11) || (z & UINT64_C(0x8000000000000000)))
2068+
{
2069+
raiseFlags(flag_invalid);
2070+
return sign ? i64_fromNegOverflow : i64_fromPosOverflow;
2071+
}
2072+
return sign ? -(int_fast64_t)z : (int_fast64_t)z;
2073+
}
2074+
else {
2075+
if (shiftDist < 64)
2076+
return
2077+
softfloat_roundToI64(
2078+
sign, sig >> shiftDist, sig << (-shiftDist & 63), roundingMode, exact);
2079+
else
2080+
return
2081+
softfloat_roundToI64(
2082+
sign, 0, (shiftDist == 64) ? sig : (sig != 0), roundingMode, exact);
2083+
}
2084+
}
2085+
20292086
static int_fast32_t f64_to_i32_r_minMag( float64_t a, bool exact )
20302087
{
20312088
uint_fast64_t uiA;
@@ -3076,6 +3133,46 @@ static int_fast32_t
30763133
return sign ? i32_fromNegOverflow : i32_fromPosOverflow;
30773134
}
30783135

3136+
static int_fast64_t
3137+
softfloat_roundToI64(
3138+
bool sign, uint_fast64_t sig, uint_fast64_t sigExtra, uint_fast8_t roundingMode, bool exact )
3139+
{
3140+
bool roundNearEven, doIncrement;
3141+
union { uint64_t ui; int64_t i; } uZ;
3142+
int_fast64_t z;
3143+
3144+
/*------------------------------------------------------------------------
3145+
*------------------------------------------------------------------------*/
3146+
roundNearEven = (roundingMode == round_near_even);
3147+
doIncrement = (UINT64_C(0x8000000000000000) <= sigExtra);
3148+
if (!roundNearEven && (roundingMode != round_near_maxMag)) {
3149+
doIncrement =
3150+
(roundingMode
3151+
== (sign ? round_min : round_max))
3152+
&& sigExtra;
3153+
}
3154+
if (doIncrement) {
3155+
++sig;
3156+
if (!sig) goto invalid;
3157+
sig &=
3158+
~(uint_fast64_t)
3159+
(!(sigExtra & UINT64_C(0x7FFFFFFFFFFFFFFF))
3160+
& roundNearEven);
3161+
}
3162+
uZ.ui = sign ? (~sig + 1) : sig;
3163+
z = uZ.i;
3164+
if (z && ((z < 0) ^ sign)) goto invalid;
3165+
if (exact && sigExtra) {
3166+
raiseFlags(flag_inexact);
3167+
}
3168+
return z;
3169+
/*------------------------------------------------------------------------
3170+
*------------------------------------------------------------------------*/
3171+
invalid:
3172+
raiseFlags(flag_invalid);
3173+
return sign ? i64_fromNegOverflow : i64_fromPosOverflow;
3174+
}
3175+
30793176
static struct uint128
30803177
softfloat_shiftRightJam128( uint64_t a64, uint64_t a0, uint_fast32_t dist )
30813178
{

modules/core/test/test_math.cpp

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3736,4 +3736,130 @@ TEST(Core_SoftFloat, sincos64)
37363736
}
37373737
}
37383738

3739+
TEST(Core_SoftFloat, CvRound)
3740+
{
3741+
struct
3742+
{
3743+
uint64_t inVal;
3744+
int64_t out64;
3745+
int32_t out32;
3746+
} _values[] =
3747+
{
3748+
{ 0x0123456789abcdefU, 0, 0 }, // 3.51270056408850369812238561681E-303
3749+
{ 0x0000000000000000U, 0, 0 }, // 0
3750+
{ 0x8000000000000000U, 0, 0 }, // -0
3751+
{ 0x000123456789abcdU, 0, 0 }, // 1.5822747438273385725152200433E-309
3752+
{ 0x800123456789abcdU, 0, 0 }, // -1.5822747438273385725152200433E-309
3753+
{ 0x7ff0000000000000U, INT64_MAX, INT32_MAX }, // +inf
3754+
{ 0xfff0000000000000U, INT64_MIN, INT32_MIN }, // -inf
3755+
{ 0x7ff0000000000001U, INT64_MAX, INT32_MAX }, // nan(casts to maximum value)
3756+
{ 0xfff0000000000001U, INT64_MAX, INT32_MAX }, // nan(casts to maximum value)
3757+
{ 0x7ffa5a5a5a5a5a5aU, INT64_MAX, INT32_MAX }, // nan(casts to maximum value)
3758+
{ 0xfffa5a5a5a5a5a5aU, INT64_MAX, INT32_MAX }, // nan(casts to maximum value)
3759+
{ 0x7fe123456789abcdU, INT64_MAX, INT32_MAX }, // 9.627645455595956656406699747E307
3760+
{ 0xffe123456789abcdU, INT64_MIN, INT32_MIN }, // -9.627645455595956656406699747E307
3761+
{ 0x43ffffffffffffffU, INT64_MAX, INT32_MAX }, // (2^53-1)*2^12
3762+
{ 0xc3ffffffffffffffU, INT64_MIN, INT32_MIN }, // -(2^53-1)*2^12
3763+
{ 0x43f0000000000000U, INT64_MAX, INT32_MAX }, // 2^64
3764+
{ 0xc3f0000000000000U, INT64_MIN, INT32_MIN }, // -2^64
3765+
{ 0x43efffffffffffffU, INT64_MAX, INT32_MAX }, // (2^53-1)*2^11
3766+
{ 0xc3efffffffffffffU, INT64_MIN, INT32_MIN }, // -(2^53-1)*2^11
3767+
{ 0x43e0000000000000U, INT64_MAX, INT32_MAX }, // 2^63
3768+
{ 0xc3e0000000000000U, -0x7fffffffffffffff-1, INT32_MIN }, // -2^63
3769+
{ 0x43dfffffffffffffU, 0x7ffffffffffffc00, INT32_MAX }, // (2^53-1)*2^10
3770+
{ 0xc3dfffffffffffffU, -0x7ffffffffffffc00, INT32_MIN }, // -(2^53-1)*2^10
3771+
{ 0x433fffffffffffffU, 0x1fffffffffffff, INT32_MAX }, // (2^53-1)
3772+
{ 0xc33fffffffffffffU, -0x1fffffffffffff, INT32_MIN }, // -(2^53-1)
3773+
{ 0x432fffffffffffffU, 0x10000000000000, INT32_MAX }, // (2^52-1) + 0.5
3774+
{ 0xc32fffffffffffffU, -0x10000000000000, INT32_MIN }, // -(2^52-1) - 0.5
3775+
{ 0x431fffffffffffffU, 0x8000000000000, INT32_MAX }, // (2^51-1) + 0.75
3776+
{ 0xc31fffffffffffffU, -0x8000000000000, INT32_MIN }, // -(2^51-1) - 0.75
3777+
{ 0x431ffffffffffffeU, 0x8000000000000, INT32_MAX }, // (2^51-1) + 0.5
3778+
{ 0xc31ffffffffffffeU, -0x8000000000000, INT32_MIN }, // -(2^51-1) - 0.5
3779+
{ 0x431ffffffffffffdU, 0x7ffffffffffff, INT32_MAX }, // (2^51-1) + 0.25
3780+
{ 0xc31ffffffffffffdU, -0x7ffffffffffff, INT32_MIN }, // -(2^51-1) - 0.25
3781+
3782+
{ 0x41f0000000000000U, 0x100000000, INT32_MAX }, // 2^32 = 4294967296
3783+
{ 0xc1f0000000000000U, -0x100000000, INT32_MIN }, // -2^32 = -4294967296
3784+
{ 0x41efffffffffffffU, 0x100000000, INT32_MAX }, // 4294967295.99999952316284179688
3785+
{ 0xc1efffffffffffffU, -0x100000000, INT32_MIN }, // -4294967295.99999952316284179688
3786+
{ 0x41effffffff00000U, 0x100000000, INT32_MAX }, // (2^32-1) + 0.5 = 4294967295.5
3787+
{ 0xc1effffffff00000U, -0x100000000, INT32_MIN }, // -(2^32-1) - 0.5 = -4294967295.5
3788+
{ 0x41efffffffe00000U, 0xffffffffll, INT32_MAX }, // (2^32-1)
3789+
{ 0xc1efffffffe00000U, -0xffffffffll, INT32_MIN }, // -(2^32-1)
3790+
{ 0x41e0000000000000U, 0x80000000ll, INT32_MAX }, // 2^31 = 2147483648
3791+
{ 0xc1e0000000000000U, -0x80000000ll, -0x7fffffff-1 }, // -2^31 = -2147483648
3792+
{ 0x41dfffffffffffffU, 0x80000000ll, INT32_MAX }, // 2147483647.99999976158142089844
3793+
{ 0xc1dfffffffffffffU, -0x80000000ll, -0x7fffffff-1 }, // -2147483647.99999976158142089844
3794+
3795+
{ 0x41dffffffff00000U, 0x80000000ll, INT32_MAX }, // (2^31-1) + 0.75
3796+
{ 0xc1dffffffff00000U, -0x80000000ll, -0x7fffffff-1 }, // -(2^31-1) - 0.75
3797+
{ 0x41dfffffffe00001U, 0x80000000ll, INT32_MAX }, // (2^31-1) + 0.5 + 2^-22
3798+
{ 0xc1dfffffffe00001U, -0x80000000ll, -0x7fffffff-1 }, // -(2^31-1) - 0.5 - 2^-22
3799+
{ 0x41dfffffffe00000U, 0x80000000ll, INT32_MAX }, // (2^31-1) + 0.5
3800+
{ 0xc1dfffffffe00000U, -0x80000000ll, -0x7fffffff-1 }, // -(2^31-1) - 0.5
3801+
{ 0x41dfffffffdfffffU, 0x7fffffff, 0x7fffffff }, // (2^31-1) + 0.5 - 2^-22
3802+
{ 0xc1dfffffffdfffffU, -0x7fffffff, -0x7fffffff }, // -(2^31-1) - 0.5 + 2^-22
3803+
{ 0x41dfffffffd00000U, 0x7fffffff, 0x7fffffff }, // (2^31-1) + 0.25
3804+
{ 0xc1dfffffffd00000U, -0x7fffffff, -0x7fffffff }, // -(2^31-1) - 0.25
3805+
{ 0x41dfffffffc00000U, 0x7fffffff, 0x7fffffff }, // (2^31-1)
3806+
{ 0xc1dfffffffc00000U, -0x7fffffff, -0x7fffffff }, // -(2^31-1)
3807+
{ 0x41d0000000000000U, 0x40000000, 0x40000000 }, // 2^30 = 2147483648
3808+
{ 0xc1d0000000000000U, -0x40000000, -0x40000000 }, // -2^30 = -2147483648
3809+
3810+
{ 0x4006000000000000U, 3, 3 }, // 2.75
3811+
{ 0xc006000000000000U, -3, -3 }, // -2.75
3812+
{ 0x4004000000000001U, 3, 3 }, // 2.5 + 2^-51
3813+
{ 0xc004000000000001U, -3, -3 }, // -2.5 - 2^-51
3814+
{ 0x4004000000000000U, 2, 2 }, // 2.5
3815+
{ 0xc004000000000000U, -2, -2 }, // -2.5
3816+
{ 0x4003ffffffffffffU, 2, 2 }, // 2.5 - 2^-51
3817+
{ 0xc003ffffffffffffU, -2, -2 }, // -2.5 + 2^-51
3818+
{ 0x4002000000000000U, 2, 2 }, // 2.25
3819+
{ 0xc002000000000000U, -2, -2 }, // -2.25
3820+
3821+
{ 0x3ffc000000000000U, 2, 2 }, // 1.75
3822+
{ 0xbffc000000000000U, -2, -2 }, // -1.75
3823+
{ 0x3ff8000000000001U, 2, 2 }, // 1.5 + 2^-52
3824+
{ 0xbff8000000000001U, -2, -2 }, // -1.5 - 2^-52
3825+
{ 0x3ff8000000000000U, 2, 2 }, // 1.5
3826+
{ 0xbff8000000000000U, -2, -2 }, // -1.5
3827+
{ 0x3ff7ffffffffffffU, 1, 1 }, // 1.5 - 2^-52
3828+
{ 0xbff7ffffffffffffU, -1, -1 }, // -1.5 + 2^-52
3829+
{ 0x3ff4000000000000U, 1, 1 }, // 1.25
3830+
{ 0xbff4000000000000U, -1, -1 }, // -1.25
3831+
3832+
{ 0x3fe8000000000000U, 1, 1 }, // 0.75
3833+
{ 0xbfe8000000000000U, -1, -1 }, // -0.75
3834+
{ 0x3fe0000000000001U, 1, 1 }, // 0.5 + 2^-53
3835+
{ 0xbfe0000000000001U, -1, -1 }, // -0.5 - 2^-53
3836+
{ 0x3fe0000000000000U, 0, 0 }, // 0.5
3837+
{ 0xbfe0000000000000U, 0, 0 }, // -0.5
3838+
3839+
{ 0x3fd8000000000000U, 0, 0 }, // 0.375
3840+
{ 0xbfd8000000000000U, 0, 0 }, // -0.375
3841+
{ 0x3fd0000000000000U, 0, 0 }, // 0.25
3842+
{ 0xbfd0000000000000U, 0, 0 }, // -0.25
3843+
3844+
{ 0x0ff123456789abcdU, 0, 0 }, // 6.89918601543515033558134828315E-232
3845+
{ 0x8ff123456789abcdU, 0, 0 } // -6.89918601543515033558134828315E-232
3846+
};
3847+
struct testvalues
3848+
{
3849+
softdouble inVal;
3850+
int64_t out64;
3851+
int32_t out32;
3852+
} *values = (testvalues*)_values;
3853+
3854+
for (int i = 0, maxi = sizeof(_values) / sizeof(_values[0]); i < maxi; i++)
3855+
{
3856+
EXPECT_EQ(values[i].out64, cvRound64(values[i].inVal));
3857+
EXPECT_EQ(values[i].out64, saturate_cast<int64_t>(values[i].inVal));
3858+
EXPECT_EQ((uint64_t)(values[i].out64), saturate_cast<uint64_t>(values[i].inVal));
3859+
EXPECT_EQ(values[i].out32, cvRound(values[i].inVal));
3860+
EXPECT_EQ(values[i].out32, saturate_cast<int32_t>(values[i].inVal));
3861+
EXPECT_EQ((uint32_t)(values[i].out32), saturate_cast<uint32_t>(values[i].inVal));
3862+
}
3863+
}
3864+
37393865
/* End of file. */

0 commit comments

Comments
 (0)