It looks like FloatAlmostEqual function (itkMath.h) does rather similar thing twice, in particular if floats are not almost equal - subtract, abs, compare (first to epsilon, then unit of least precision), isn’t it? It is not wrong, but may be it could impact performance?
I think this is intended. A pair of floating point numbers could have a large absolute difference, and still be considered “almost equal”:
EXPECT_TRUE( itk::Math::FloatAlmostEqual( 1.7976931348623158e+308, // <== Which is DBL_MAX. 1.7976931348623156e+308 // <== Mind the last decimal digit! ));
In this case, the absolute difference is ~2.0e+292, while these two numbers only differ by one unit of least precision (ULP).
On the other hand, a pair of floating point numbers could have a large absolute ULP difference, and still be considered “almost equal”:
EXPECT_TRUE( itk::Math::FloatAlmostEqual( 2.2250738585072014e-308, // <== Which is DBL_MIN. 0.0 ));
My debugger tells me that DBL_MIN is 4503599627370496 ULPs apart from 0.0, yet these numbers could be considered almost equal, right?
That’s possible, of course. But do you have a specific application or image filter in mind, whose performance could be affected by this function?
Thank you for explanation.
But do you have a specific application or image filter in mind, whose performance could be affected by this function?
./Modules/Numerics/Statistics/include/itkHistogramToTextureFeaturesFilter.hxx: if( Math::FloatAlmostEqual( pixelVarianceSquared, 0.0, 4, 2*NumericTraits<double>::epsilon() ) ) ./Modules/Filtering/Thresholding/include/itkOtsuMultipleThresholdsCalculator.hxx: !Math::FloatAlmostEqual( maxVarBetween, varBetween, maxUlps) ) ./Modules/Filtering/ImageFrequency/include/itkFrequencyBandImageFilter.hxx: if ( Math::FloatAlmostEqual(scalarFrequency, this->m_LowFrequencyThreshold) ) ./Modules/Filtering/ImageFrequency/include/itkFrequencyBandImageFilter.hxx: if ( Math::FloatAlmostEqual(scalarFrequency, this->m_HighFrequencyThreshold) ) ./Modules/Filtering/Path/include/itkPolyLineParametricPath.hxx: if ( input > endPoint || itk::Math::FloatAlmostEqual( input, endPoint ) ) ./Modules/Filtering/FastMarching/include/itkFastMarchingImageFilterBase.hxx: if (itk::Math::FloatAlmostEqual<double>(cc, 0.0)) ./Modules/Core/Common/include/itkVersor.hxx: if ( Math::FloatAlmostEqual<T>(vectorNorm, 0.0) ) ./Modules/Core/Transform/include/itkBSplineTransform.hxx: if( Math::FloatAlmostEqual( index[j], maxLimit, 4 ) ) ./Modules/Core/Transform/include/itkVersorRigid3DTransform.hxx: if (Math::FloatAlmostEqual<TParametersValueType>(norm, 0.0))
Edit: removed calls from tests
Interesting. I think you’re right: it seems to me that in some of these cases, the performance could be improved by doing something else than calling the current
FloatAlmostEqual function. For example, instead of
FloatAlmostEqual(x, 0.0), I think I would prefer something like
abs(x) < DBL_MIN. But I haven’t had a close look yet at these particular cases.
You are right, in some cases
FloatAlmostEqual could be replaced by less general
std::abs(x)<epsilon. But as that case is checked first in
FloatAlmostEqual, and it should be in the predicted branch, the extra code in
FloatAlmostEqual should not matter. Of course, to test this assumption a change should be made and performance compared with and without the change.