Mat::operator=(const Scalar&) incorrectly handles NaNs with floating-point images when GCC's -ffast-math flag is enabled (Bug #2056)


Added by Ose Pedro over 12 years ago. Updated about 12 years ago.


Status:Done Start date:2012-06-15
Priority:Normal Due date:
Assignee:Vadim Pisarevsky % Done:

0%

Category:core
Target version:2.4.3
Affected version: Operating System:
Difficulty: HW Platform:
Pull request:

Description

The

if( s[0] == 0 && s[1] == 0 && s[2] == 0 && s[3] == 0 )
test in modules/core/src/copy.cpp's definition of Mat::operator=(const Scalar& s) evaluates to true when s contains NaNs and -ffast-math is enabled, resulting in the input Mat being filled with zeros rather than NaNs. Compiling the following code against a version of OpenCV built with -ffast-math reproduces the problem:

// Define a NaN value
union {
  float f;
  uint32_t i;
} nan;
nan.i=0x7FC00000;

// Assign nan.f to image
cv::Mat nanTest(1,1,CV_32FC1);
nanTest=cv::Scalar(nan.f);

// Print results
std::cout<<"nan.f="<<nan.f<<std::endl;
std::cout<<"nanTest.at<float>(0,0)="<<nanTest.at<float>(0,0)<<std::endl;

To show that -ffast-math is the cause of the problem, compile the following program:

#include <iostream>
#include <cstdint>

int main(int argc, char** argv) {
  union {
    float f;
    uint32_t i;
  } nan;
  nan.i=0x7FC00000;

  std::cout<<"nan.f==0 = "<<(nan.f==0)<<std::endl;

  return 0;
}

with
g++ -std=c++0x -ffast-math -o TestFastMath Test.cpp && g++ -std=c++0x -o Test Test.cpp

./Test produces the output nan.f==0 = 0, whereas ./TestFastMath produces the output nan.f==0 = 1.

The problem occurs with the build of OpenCV 2.3.1 that's available from the Ubuntu 12.04 repository, which I presume was built with -ffast-math enabled. I have just downloaded and built OpenCV 2.4.1, and -ffast-math was disabled by default, so the problem does not occur. If you must allow users to build OpenCV with -ffast-math, please consider using something like the following function to test whether or not the cv::Scalar is zero instead:

inline bool isZero(const double v) {
  union {double d; uint64_t i;} u;
  u.d=v;
  return u.i==0;
}


Associated revisions

Revision df8364ce
Added by Vadim Pisarevsky over 12 years ago

Fixed "arr = NaN" case (bug #2056)

Revision 8fe79738
Added by Roman Donchenko about 11 years ago

Merge pull request #2056 from asmorkalov:java_core_cuda_wrappers

History

Updated by Ose Pedro over 12 years ago

Or alternatively, given that there are probably a lot of places in OpenCV where a floating-point number is compared to a literal, perhaps it would be more generally helpful to put a warning somewhere in the documentation about the use of -ffast-math with NaNs?

Updated by Ose Pedro over 12 years ago

Oh, in fact http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html says that -ffast-math enables -ffinite-math-only, which "Allow[s] optimizations for floating-point arithmetic that assume that arguments and results are not NaNs or +-Infs". Compiling the example program I gave above with -ffinite-math-only instead of -ffast-math shows that -ffinite-math-only is in fact the root cause of the problem.

Updated by Andrey Kamaev over 12 years ago

Vadim, are we supporting -ffast-math?

  • Category set to build/install
  • Assignee set to Vadim Pisarevsky

Updated by Vadim Pisarevsky over 12 years ago

  • Target version deleted ()
  • Category changed from build/install to core
  • Assignee deleted (Vadim Pisarevsky)

Updated by Vadim Pisarevsky over 12 years ago

fixed in df8364ce

  • Status changed from Open to Done
  • Assignee set to Vadim Pisarevsky

Updated by Andrey Kamaev about 12 years ago

  • Target version set to 2.4.3

Also available in: Atom PDF