Skip to content

div: inconsistent div-by-zero behavior #21044

@alalek

Description

@alalek

#8413 issue forces to use IEEE 754 rules for floating points.
#12826 implements that (OpenCV 4.0.0).

However there is implicit conversion to float+ type if src/dst types does not match:

wtype = std::max(depth1, std::max(depth2, CV_32F));
wtype = std::max(wtype, dtype);

So processing is performed by IEEE rules, which may emit Inf/NaN values.

Conversion of result float values to destination of integer signed type (8S/16S/32S) may emit "min" values (-128, -32768, INT_MIN) which may be not expected by Users.

Problem comes from cvRound(nan/inf/int32 overflow/int32 underflow) => INT_MIN (-2147483648)

std::cout << cvRound(std::numeric_limits<float>::quiet_NaN()) << std::endl;
std::cout << cvRound(std::numeric_limits<float>::infinity()) << std::endl;
std::cout << cvRound(-std::numeric_limits<float>::infinity()) << std::endl;
std::cout << cvRound(1e30f) << std::endl;
std::cout << cvRound(-1e30f) << std::endl;

Test code:

cv::Mat m1(N, N, CV_8S, Scalar::all(1));
cv::Mat m2(N, N, CV_8U, Scalar::all(0));
Mat dst;
int dstType = CV_8S;
double scale = 2.5;
cv::divide(m1, m2, dst, scale, dstType);
std::cout << dst.type() << std::endl << dst << std::endl;  // -128

The same types works as documented:

cv::Mat m1(N, N, CV_8S, Scalar::all(1));
cv::Mat m2(N, N, CV_8S, Scalar::all(0));
Mat dst;
int dstType = CV_8S;
double scale = 2.5;
cv::divide(m1, m2, dst, scale, dstType);
std::cout << dst.type() << std::endl << dst << std::endl;  // 0 as expected

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions