1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-28 23:03:03 +04:00

Added implementation of softdouble rounding to int64_t

This commit is contained in:
Vitaly Tuzov
2017-12-08 15:38:22 +03:00
parent a2811d93dd
commit 86b128dbb3
3 changed files with 233 additions and 1 deletions
+97
View File
@@ -183,6 +183,7 @@ static bool f32_lt( float32_t, float32_t );
| 64-bit (double-precision) floating-point operations.
*----------------------------------------------------------------------------*/
static int_fast32_t f64_to_i32( float64_t, uint_fast8_t, bool );
static int_fast64_t f64_to_i64( float64_t, uint_fast8_t, bool );
static int_fast32_t f64_to_i32_r_minMag( float64_t, bool );
static float32_t f64_to_f32( float64_t );
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
int cvFloor(const cv::softdouble& a) { return cv::f64_to_i32(a, cv::round_min, false); }
int cvCeil (const cv::softdouble& a) { return cv::f64_to_i32(a, cv::round_max, false); }
int64_t cvRound64(const cv::softdouble& a) { return cv::f64_to_i64(a, cv::round_near_even, false); }
namespace cv
{
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
/*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/
static int_fast64_t softfloat_roundToI64( bool, uint_fast64_t, uint_fast64_t, uint_fast8_t, bool);
struct exp16_sig64 { int_fast16_t exp; uint_fast64_t sig; };
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
return softfloat_roundToI32( sign, sig, roundingMode, exact );
}
static int_fast64_t f64_to_i64(float64_t a, uint_fast8_t roundingMode, bool exact )
{
uint_fast64_t uiA;
bool sign;
int_fast16_t exp;
uint_fast64_t sig;
int_fast16_t shiftDist;
/*------------------------------------------------------------------------
*------------------------------------------------------------------------*/
uiA = a.v;
sign = signF64UI(uiA);
exp = expF64UI(uiA);
sig = fracF64UI(uiA);
/*------------------------------------------------------------------------
*------------------------------------------------------------------------*/
#if (i64_fromNaN != i64_fromPosOverflow) || (i64_fromNaN != i64_fromNegOverflow)
if ((exp == 0x7FF) && sig) {
#if (i64_fromNaN == i64_fromPosOverflow)
sign = 0;
#elif (i64_fromNaN == i64_fromNegOverflow)
sign = 1;
#else
raiseFlags(flag_invalid);
return i64_fromNaN;
#endif
}
#endif
/*------------------------------------------------------------------------
*------------------------------------------------------------------------*/
if (exp) sig |= UINT64_C(0x0010000000000000);
shiftDist = 0x433 - exp;
if (shiftDist <= 0) {
uint_fast64_t z = sig << -shiftDist;
if ((shiftDist < -11) || (z & UINT64_C(0x8000000000000000)))
{
raiseFlags(flag_invalid);
return sign ? i64_fromNegOverflow : i64_fromPosOverflow;
}
return sign ? -(int_fast64_t)z : (int_fast64_t)z;
}
else {
if (shiftDist < 64)
return
softfloat_roundToI64(
sign, sig >> shiftDist, sig << (-shiftDist & 63), roundingMode, exact);
else
return
softfloat_roundToI64(
sign, 0, (shiftDist == 64) ? sig : (sig != 0), roundingMode, exact);
}
}
static int_fast32_t f64_to_i32_r_minMag( float64_t a, bool exact )
{
uint_fast64_t uiA;
@@ -3076,6 +3133,46 @@ static int_fast32_t
return sign ? i32_fromNegOverflow : i32_fromPosOverflow;
}
static int_fast64_t
softfloat_roundToI64(
bool sign, uint_fast64_t sig, uint_fast64_t sigExtra, uint_fast8_t roundingMode, bool exact )
{
bool roundNearEven, doIncrement;
union { uint64_t ui; int64_t i; } uZ;
int_fast64_t z;
/*------------------------------------------------------------------------
*------------------------------------------------------------------------*/
roundNearEven = (roundingMode == round_near_even);
doIncrement = (UINT64_C(0x8000000000000000) <= sigExtra);
if (!roundNearEven && (roundingMode != round_near_maxMag)) {
doIncrement =
(roundingMode
== (sign ? round_min : round_max))
&& sigExtra;
}
if (doIncrement) {
++sig;
if (!sig) goto invalid;
sig &=
~(uint_fast64_t)
(!(sigExtra & UINT64_C(0x7FFFFFFFFFFFFFFF))
& roundNearEven);
}
uZ.ui = sign ? (~sig + 1) : sig;
z = uZ.i;
if (z && ((z < 0) ^ sign)) goto invalid;
if (exact && sigExtra) {
raiseFlags(flag_inexact);
}
return z;
/*------------------------------------------------------------------------
*------------------------------------------------------------------------*/
invalid:
raiseFlags(flag_invalid);
return sign ? i64_fromNegOverflow : i64_fromPosOverflow;
}
static struct uint128
softfloat_shiftRightJam128( uint64_t a64, uint64_t a0, uint_fast32_t dist )
{