New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
imgproc: fix fixedpoint #11395
imgproc: fix fixedpoint #11395
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -55,9 +55,11 @@ class fixedpoint64 | |
CV_ALWAYS_INLINE fixedpoint64 operator * (const int32_t& val2) const { return operator *(fixedpoint64(val2)); } | ||
CV_ALWAYS_INLINE fixedpoint64 operator * (const fixedpoint64& val2) const | ||
{ | ||
uint64_t uval = (uint64_t)((val ^ (val >> 63)) - (val >> 63)); | ||
uint64_t umul = (uint64_t)((val2.val ^ (val2.val >> 63)) - (val2.val >> 63)); | ||
int64_t ressign = (val >> 63) ^ (val2.val >> 63); | ||
bool sign_val = val < 0; | ||
bool sign_mul = val2.val < 0; | ||
uint64_t uval = sign_val ? (uint64_t)(-val) : (uint64_t)val; | ||
uint64_t umul = sign_mul ? (uint64_t)(-val2.val) : (uint64_t)val2.val; | ||
bool ressign = sign_val ^ sign_mul; | ||
|
||
uint64_t sh0 = fixedround((uval & 0xFFFFFFFF) * (umul & 0xFFFFFFFF)); | ||
uint64_t sh1_0 = (uval >> 32) * (umul & 0xFFFFFFFF); | ||
|
@@ -67,33 +69,37 @@ class fixedpoint64 | |
uint64_t val0_h = (sh2 & 0xFFFFFFFF) + (sh1_0 >> 32) + (sh1_1 >> 32) + (val0_l >> 32); | ||
val0_l &= 0xFFFFFFFF; | ||
|
||
if ( (sh2 >> 32) || (val0_h >> ressign ? 32 : 31) ) | ||
return (ressign ? ~(int64_t)0x7FFFFFFFFFFFFFFF : (int64_t)0x7FFFFFFFFFFFFFFF); | ||
if (sh2 > CV_BIG_INT(0x7FFFFFFF) || val0_h > CV_BIG_INT(0x7FFFFFFF)) | ||
return (int64_t)(ressign ? CV_BIG_UINT(0x8000000000000000) : CV_BIG_INT(0x7FFFFFFFFFFFFFFF)); | ||
|
||
if (ressign) | ||
{ | ||
val0_l = (~val0_l + 1) & 0xFFFFFFFF; | ||
val0_h = val0_l ? ~val0_h : (~val0_h + 1); | ||
return -(int64_t)(val0_h << 32 | val0_l); | ||
} | ||
return (int64_t)(val0_h << 32 | val0_l); | ||
} | ||
CV_ALWAYS_INLINE fixedpoint64 operator + (const fixedpoint64& val2) const | ||
{ | ||
int64_t res = val + val2.val; | ||
return ((val ^ res) & (val2.val ^ res)) >> 63 ? ~(res & ~0x7FFFFFFFFFFFFFFF) : res; | ||
return (int64_t)(((val ^ res) & (val2.val ^ res)) < 0 ? ~(res & CV_BIG_UINT(0x8000000000000000)) : res); | ||
} | ||
CV_ALWAYS_INLINE fixedpoint64 operator - (const fixedpoint64& val2) const | ||
{ | ||
int64_t res = val - val2.val; | ||
return ((val ^ val2.val) & (val ^ res)) >> 63 ? ~(res & ~0x7FFFFFFFFFFFFFFF) : res; | ||
return (int64_t)(((val ^ val2.val) & (val ^ res)) < 0 ? ~(res & CV_BIG_UINT(0x8000000000000000)) : res); | ||
} | ||
CV_ALWAYS_INLINE fixedpoint64 operator >> (int n) const { return fixedpoint64(val >> n); } | ||
CV_ALWAYS_INLINE fixedpoint64 operator << (int n) const { return fixedpoint64(val << n); } | ||
CV_ALWAYS_INLINE bool operator == (const fixedpoint64& val2) const { return val == val2.val; } | ||
template <typename ET> | ||
CV_ALWAYS_INLINE operator ET() const { return cv::saturate_cast<ET>((int64_t)fixedround((uint64_t)val) >> fixedShift); } | ||
CV_ALWAYS_INLINE ET saturate_cast() const { return cv::saturate_cast<ET>((int64_t)fixedround((uint64_t)val) >> fixedShift); } | ||
CV_ALWAYS_INLINE operator double() const { return (double)val / (1LL << fixedShift); } | ||
CV_ALWAYS_INLINE operator float() const { return (float)val / (1LL << fixedShift); } | ||
CV_ALWAYS_INLINE operator uint8_t() const { return saturate_cast<uint8_t>(); } | ||
CV_ALWAYS_INLINE operator int8_t() const { return saturate_cast<int8_t>(); } | ||
CV_ALWAYS_INLINE operator uint16_t() const { return saturate_cast<uint16_t>(); } | ||
CV_ALWAYS_INLINE operator int16_t() const { return saturate_cast<int16_t>(); } | ||
CV_ALWAYS_INLINE operator int32_t() const { return saturate_cast<int32_t>(); } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMHO it seems somewhat insymmetrical: int8_t/uint8_t, int16_t/uint16_t, int32_t/(void) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This set is correlated with supported cv::Mat types. IMHO, The worst problem here is low tests coverage for this file. |
||
CV_ALWAYS_INLINE bool isZero() { return val == 0; } | ||
static CV_ALWAYS_INLINE fixedpoint64 zero() { return fixedpoint64(); } | ||
static CV_ALWAYS_INLINE fixedpoint64 one() { return fixedpoint64((int64_t)(1LL << fixedShift)); } | ||
|
@@ -133,15 +139,15 @@ class ufixedpoint64 | |
uint64_t val0_h = (sh2 & 0xFFFFFFFF) + (sh1_0 >> 32) + (sh1_1 >> 32) + (val0_l >> 32); | ||
val0_l &= 0xFFFFFFFF; | ||
|
||
if ((sh2 >> 32) || (val0_h >> 32)) | ||
return ((uint64_t)0xFFFFFFFFFFFFFFFF); | ||
if (sh2 > CV_BIG_INT(0xFFFFFFFF) || val0_h > CV_BIG_INT(0xFFFFFFFF)) | ||
return (uint64_t)CV_BIG_UINT(0xFFFFFFFFFFFFFFFF); | ||
|
||
return val0_h << 32 | val0_l; | ||
return (val0_h << 32 | val0_l); | ||
} | ||
CV_ALWAYS_INLINE ufixedpoint64 operator + (const ufixedpoint64& val2) const | ||
{ | ||
uint64_t res = val + val2.val; | ||
return (val > res) ? (uint64_t)0xFFFFFFFFFFFFFFFF : res; | ||
return (uint64_t)((val > res) ? CV_BIG_UINT(0xFFFFFFFFFFFFFFFF) : res); | ||
} | ||
CV_ALWAYS_INLINE ufixedpoint64 operator - (const ufixedpoint64& val2) const | ||
{ | ||
|
@@ -151,9 +157,14 @@ class ufixedpoint64 | |
CV_ALWAYS_INLINE ufixedpoint64 operator << (int n) const { return ufixedpoint64(val << n); } | ||
CV_ALWAYS_INLINE bool operator == (const ufixedpoint64& val2) const { return val == val2.val; } | ||
template <typename ET> | ||
CV_ALWAYS_INLINE operator ET() const { return cv::saturate_cast<ET>(fixedround(val) >> fixedShift); } | ||
CV_ALWAYS_INLINE ET saturate_cast() const { return cv::saturate_cast<ET>(fixedround(val) >> fixedShift); } | ||
CV_ALWAYS_INLINE operator double() const { return (double)val / (1LL << fixedShift); } | ||
CV_ALWAYS_INLINE operator float() const { return (float)val / (1LL << fixedShift); } | ||
CV_ALWAYS_INLINE operator uint8_t() const { return saturate_cast<uint8_t>(); } | ||
CV_ALWAYS_INLINE operator int8_t() const { return saturate_cast<int8_t>(); } | ||
CV_ALWAYS_INLINE operator uint16_t() const { return saturate_cast<uint16_t>(); } | ||
CV_ALWAYS_INLINE operator int16_t() const { return saturate_cast<int16_t>(); } | ||
CV_ALWAYS_INLINE operator int32_t() const { return saturate_cast<int32_t>(); } | ||
CV_ALWAYS_INLINE bool isZero() { return val == 0; } | ||
static CV_ALWAYS_INLINE ufixedpoint64 zero() { return ufixedpoint64(); } | ||
static CV_ALWAYS_INLINE ufixedpoint64 one() { return ufixedpoint64((uint64_t)(1ULL << fixedShift)); } | ||
|
@@ -187,21 +198,26 @@ class fixedpoint32 | |
CV_ALWAYS_INLINE fixedpoint32 operator + (const fixedpoint32& val2) const | ||
{ | ||
int32_t res = val + val2.val; | ||
return ((val ^ res) & (val2.val ^ res)) >> 31 ? ~(res & ~0x7FFFFFFF) : res; | ||
return (int64_t)((val ^ res) & (val2.val ^ res)) >> 31 ? ~(res & ~0x7FFFFFFF) : res; | ||
} | ||
CV_ALWAYS_INLINE fixedpoint32 operator - (const fixedpoint32& val2) const | ||
{ | ||
int32_t res = val - val2.val; | ||
return ((val ^ val2.val) & (val ^ res)) >> 31 ? ~(res & ~0x7FFFFFFF) : res; | ||
return (int64_t)((val ^ val2.val) & (val ^ res)) >> 31 ? ~(res & ~0x7FFFFFFF) : res; | ||
} | ||
CV_ALWAYS_INLINE fixedpoint32 operator >> (int n) const { return fixedpoint32(val >> n); } | ||
CV_ALWAYS_INLINE fixedpoint32 operator << (int n) const { return fixedpoint32(val << n); } | ||
CV_ALWAYS_INLINE bool operator == (const fixedpoint32& val2) const { return val == val2.val; } | ||
template <typename ET> | ||
CV_ALWAYS_INLINE operator ET() const { return cv::saturate_cast<ET>((int32_t)fixedround((uint32_t)val) >> fixedShift); } | ||
CV_ALWAYS_INLINE ET saturate_cast() const { return cv::saturate_cast<ET>((int32_t)fixedround((uint32_t)val) >> fixedShift); } | ||
CV_ALWAYS_INLINE operator fixedpoint64() const { return (int64_t)val << (fixedpoint64::fixedShift - fixedShift); } | ||
CV_ALWAYS_INLINE operator double() const { return (double)val / (1 << fixedShift); } | ||
CV_ALWAYS_INLINE operator float() const { return (float)val / (1 << fixedShift); } | ||
CV_ALWAYS_INLINE operator uint8_t() const { return saturate_cast<uint8_t>(); } | ||
CV_ALWAYS_INLINE operator int8_t() const { return saturate_cast<int8_t>(); } | ||
CV_ALWAYS_INLINE operator uint16_t() const { return saturate_cast<uint16_t>(); } | ||
CV_ALWAYS_INLINE operator int16_t() const { return saturate_cast<int16_t>(); } | ||
CV_ALWAYS_INLINE operator int32_t() const { return saturate_cast<int32_t>(); } | ||
CV_ALWAYS_INLINE bool isZero() { return val == 0; } | ||
static CV_ALWAYS_INLINE fixedpoint32 zero() { return fixedpoint32(); } | ||
static CV_ALWAYS_INLINE fixedpoint32 one() { return fixedpoint32((1 << fixedShift)); } | ||
|
@@ -242,10 +258,15 @@ class ufixedpoint32 | |
CV_ALWAYS_INLINE ufixedpoint32 operator << (int n) const { return ufixedpoint32(val << n); } | ||
CV_ALWAYS_INLINE bool operator == (const ufixedpoint32& val2) const { return val == val2.val; } | ||
template <typename ET> | ||
CV_ALWAYS_INLINE operator ET() const { return cv::saturate_cast<ET>(fixedround(val) >> fixedShift); } | ||
CV_ALWAYS_INLINE ET saturate_cast() const { return cv::saturate_cast<ET>(fixedround(val) >> fixedShift); } | ||
CV_ALWAYS_INLINE operator ufixedpoint64() const { return (uint64_t)val << (ufixedpoint64::fixedShift - fixedShift); } | ||
CV_ALWAYS_INLINE operator double() const { return (double)val / (1 << fixedShift); } | ||
CV_ALWAYS_INLINE operator float() const { return (float)val / (1 << fixedShift); } | ||
CV_ALWAYS_INLINE operator uint8_t() const { return saturate_cast<uint8_t>(); } | ||
CV_ALWAYS_INLINE operator int8_t() const { return saturate_cast<int8_t>(); } | ||
CV_ALWAYS_INLINE operator uint16_t() const { return saturate_cast<uint16_t>(); } | ||
CV_ALWAYS_INLINE operator int16_t() const { return saturate_cast<int16_t>(); } | ||
CV_ALWAYS_INLINE operator int32_t() const { return saturate_cast<int32_t>(); } | ||
CV_ALWAYS_INLINE bool isZero() { return val == 0; } | ||
static CV_ALWAYS_INLINE ufixedpoint32 zero() { return ufixedpoint32(); } | ||
static CV_ALWAYS_INLINE ufixedpoint32 one() { return ufixedpoint32((1U << fixedShift)); } | ||
|
@@ -284,10 +305,15 @@ class fixedpoint16 | |
CV_ALWAYS_INLINE fixedpoint16 operator << (int n) const { return fixedpoint16((int16_t)(val << n)); } | ||
CV_ALWAYS_INLINE bool operator == (const fixedpoint16& val2) const { return val == val2.val; } | ||
template <typename ET> | ||
CV_ALWAYS_INLINE operator ET() const { return cv::saturate_cast<ET>((int16_t)fixedround((uint16_t)val) >> fixedShift); } | ||
CV_ALWAYS_INLINE ET saturate_cast() const { return cv::saturate_cast<ET>((int16_t)fixedround((uint16_t)val) >> fixedShift); } | ||
CV_ALWAYS_INLINE operator fixedpoint32() const { return (int32_t)val << (fixedpoint32::fixedShift - fixedShift); } | ||
CV_ALWAYS_INLINE operator double() const { return (double)val / (1 << fixedShift); } | ||
CV_ALWAYS_INLINE operator float() const { return (float)val / (1 << fixedShift); } | ||
CV_ALWAYS_INLINE operator uint8_t() const { return saturate_cast<uint8_t>(); } | ||
CV_ALWAYS_INLINE operator int8_t() const { return saturate_cast<int8_t>(); } | ||
CV_ALWAYS_INLINE operator uint16_t() const { return saturate_cast<uint16_t>(); } | ||
CV_ALWAYS_INLINE operator int16_t() const { return saturate_cast<int16_t>(); } | ||
CV_ALWAYS_INLINE operator int32_t() const { return saturate_cast<int32_t>(); } | ||
CV_ALWAYS_INLINE bool isZero() { return val == 0; } | ||
static CV_ALWAYS_INLINE fixedpoint16 zero() { return fixedpoint16(); } | ||
static CV_ALWAYS_INLINE fixedpoint16 one() { return fixedpoint16((int16_t)(1 << fixedShift)); } | ||
|
@@ -324,15 +350,20 @@ class ufixedpoint16 | |
CV_ALWAYS_INLINE ufixedpoint16 operator << (int n) const { return ufixedpoint16((uint16_t)(val << n)); } | ||
CV_ALWAYS_INLINE bool operator == (const ufixedpoint16& val2) const { return val == val2.val; } | ||
template <typename ET> | ||
CV_ALWAYS_INLINE operator ET() const { return cv::saturate_cast<ET>(fixedround(val) >> fixedShift); } | ||
CV_ALWAYS_INLINE ET saturate_cast() const { return cv::saturate_cast<ET>(fixedround(val) >> fixedShift); } | ||
CV_ALWAYS_INLINE operator ufixedpoint32() const { return (uint32_t)val << (ufixedpoint32::fixedShift - fixedShift); } | ||
CV_ALWAYS_INLINE operator double() const { return (double)val / (1 << fixedShift); } | ||
CV_ALWAYS_INLINE operator float() const { return (float)val / (1 << fixedShift); } | ||
CV_ALWAYS_INLINE operator uint8_t() const { return saturate_cast<uint8_t>(); } | ||
CV_ALWAYS_INLINE operator int8_t() const { return saturate_cast<int8_t>(); } | ||
CV_ALWAYS_INLINE operator uint16_t() const { return saturate_cast<uint16_t>(); } | ||
CV_ALWAYS_INLINE operator int16_t() const { return saturate_cast<int16_t>(); } | ||
CV_ALWAYS_INLINE operator int32_t() const { return saturate_cast<int32_t>(); } | ||
CV_ALWAYS_INLINE bool isZero() { return val == 0; } | ||
static CV_ALWAYS_INLINE ufixedpoint16 zero() { return ufixedpoint16(); } | ||
static CV_ALWAYS_INLINE ufixedpoint16 one() { return ufixedpoint16((uint16_t)(1 << fixedShift)); } | ||
}; | ||
|
||
} | ||
|
||
#endif | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't it be
if (sh2 > CV_BIG_UINT(0xFFFFFFFF) || val0_h > (ressign ? CV_BIG_UINT(0x80000000) : CV_BIG_INT(0x7FFFFFFF)))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Final result should be the same: saturated underflow - 0x8000'0000'0000'0000 .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry. Get the idea. The check is fine