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.