diff --git a/Modules/Core/Common/include/itkMath.h b/Modules/Core/Common/include/itkMath.h index 6d8f5233023..0507d3dcbe2 100644 --- a/Modules/Core/Common/include/itkMath.h +++ b/Modules/Core/Common/include/itkMath.h @@ -104,7 +104,7 @@ static constexpr float float_sqrteps = vnl_math::float_sqrteps; * bit, the 64 bit or the vanilla version */ #define itkTemplateFloatingToIntegerMacro(name) \ template \ - inline TReturn name(TInput x) \ + inline constexpr auto name(TInput x) \ { \ if constexpr (sizeof(TReturn) <= 4) \ { \ @@ -173,7 +173,7 @@ itkTemplateFloatingToIntegerMacro(RoundHalfIntegerUp) * \sa RoundHalfIntegerUp() */ template -inline TReturn +inline constexpr auto Round(TInput x) { return RoundHalfIntegerUp(x); @@ -208,7 +208,7 @@ itkTemplateFloatingToIntegerMacro(Ceil) #undef itkTemplateFloatingToIntegerMacro template -inline TReturn +inline auto CastWithRangeCheck(TInput x) { itkConceptMacro(OnlyDefinedForIntegerTypes1, (itk::Concept::IsInteger)); @@ -247,7 +247,7 @@ CastWithRangeCheck(TInput x) * \sa FloatAddULP */ template -inline typename Detail::FloatIEEE::IntType +inline constexpr typename Detail::FloatIEEE::IntType FloatDifferenceULP(T x1, T x2) { const Detail::FloatIEEE x1f(x1); @@ -263,7 +263,7 @@ FloatDifferenceULP(T x1, T x2) * \sa FloatDifferenceULP */ template -inline T +inline constexpr T FloatAddULP(T x, typename Detail::FloatIEEE::IntType ulps) { const Detail::FloatIEEE representInput(x); @@ -714,7 +714,7 @@ NotAlmostEquals(T1 x1, T2 x2) // The ExactlyEquals function template -inline bool +inline constexpr bool ExactlyEquals(const TInput1 & x1, const TInput2 & x2) { ITK_GCC_PRAGMA_PUSH @@ -725,7 +725,7 @@ ExactlyEquals(const TInput1 & x1, const TInput2 & x2) // The NotExactlyEquals function template -inline bool +inline constexpr bool NotExactlyEquals(const TInput1 & x1, const TInput2 & x2) { return !ExactlyEquals(x1, x2); @@ -737,33 +737,64 @@ NotExactlyEquals(const TInput1 & x1, const TInput2 & x2) * \note Negative numbers cannot be prime. */ /** @ITKStartGrouping */ -ITKCommon_EXPORT bool -IsPrime(unsigned short n); -ITKCommon_EXPORT bool -IsPrime(unsigned int n); -ITKCommon_EXPORT bool -IsPrime(unsigned long n); -ITKCommon_EXPORT bool -IsPrime(unsigned long long n); +template >> +constexpr bool +IsPrime(T n) +{ + // An Introduction to the Theory of Numbers — G.H. Hardy & E.M. Wright, 6th ed., Oxford University Press. + // See Chapter 1 (Elementary Results on Primes). The observation that primes > 3 lie in residue classes + // +/1 mod 6 follows directly from eliminating multiples of 2 and 3. + if (n <= 1) + { + return false; + } + if (n == 2 || n == 3) + { + return true; + } + if (n % 2 == 0 || n % 3 == 0) + { + return false; + } + // 6k +/- 1, and avoid overflow via i <= n / i + for (T x = 5; x <= n / x; x += 6) + { + if (n % x == 0 || n % (x + 2) == 0) + { + return false; + } + } + return true; +} /** @ITKEndGrouping */ /** Return the greatest factor of the decomposition in prime numbers. */ /** @ITKStartGrouping */ -ITKCommon_EXPORT unsigned short -GreatestPrimeFactor(unsigned short n); -ITKCommon_EXPORT unsigned int -GreatestPrimeFactor(unsigned int n); -ITKCommon_EXPORT unsigned long -GreatestPrimeFactor(unsigned long n); -ITKCommon_EXPORT unsigned long long -GreatestPrimeFactor(unsigned long long n); +template >> +constexpr T +GreatestPrimeFactor(T n) +{ + T v = 2; + while (v <= n) + { + if (n % v == 0 && IsPrime(v)) + { + n /= v; + } + else + { + v += 1; + } + } + return v; +} /** @ITKEndGrouping */ /** Returns `a * b`. Numeric overflow triggers a compilation error in * "constexpr context" and a debug assert failure at run-time. */ template -constexpr TReturnType +constexpr auto UnsignedProduct(const uintmax_t a, const uintmax_t b) noexcept { static_assert(std::is_unsigned_v, "UnsignedProduct only supports unsigned return types"); @@ -785,8 +816,8 @@ UnsignedProduct(const uintmax_t a, const uintmax_t b) noexcept * no agreed-upon value: https://en.wikipedia.org/wiki/Zero_to_the_power_of_zero */ template -constexpr TReturnType -UnsignedPower(const uintmax_t base, const uintmax_t exponent) noexcept +constexpr auto +UnsignedPower(const uintmax_t base, const uintmax_t exponent) noexcept -> TReturnType { static_assert(std::is_unsigned_v, "UnsignedPower only supports unsigned return types"); diff --git a/Modules/Core/Common/include/itkMathDetail.h b/Modules/Core/Common/include/itkMathDetail.h index 337665a16e1..689fd3a0959 100644 --- a/Modules/Core/Common/include/itkMathDetail.h +++ b/Modules/Core/Common/include/itkMathDetail.h @@ -89,7 +89,7 @@ ITK_GCC_PRAGMA_PUSH ITK_GCC_SUPPRESS_Wfloat_equal template -inline TReturn +constexpr TReturn RoundHalfIntegerToEven_base(TInput x) { if (NumericTraits::IsNonnegative(x)) @@ -106,7 +106,7 @@ RoundHalfIntegerToEven_base(TInput x) } template -inline TReturn +constexpr TReturn RoundHalfIntegerUp_base(TInput x) { x += static_cast(0.5); @@ -116,7 +116,7 @@ RoundHalfIntegerUp_base(TInput x) } template -inline TReturn +constexpr TReturn Floor_base(TInput x) { const auto r = static_cast(x); @@ -126,7 +126,7 @@ Floor_base(TInput x) } template -inline TReturn +constexpr TReturn Ceil_base(TInput x) { const auto r = static_cast(x); @@ -217,15 +217,11 @@ RoundHalfIntegerToEven_32(float x) #else // Base implementation -inline int32_t -RoundHalfIntegerToEven_32(double x) +template +constexpr int32_t +RoundHalfIntegerToEven_32(TInput x) { - return RoundHalfIntegerToEven_base(x); -} -inline int32_t -RoundHalfIntegerToEven_32(float x) -{ - return RoundHalfIntegerToEven_base(x); + return RoundHalfIntegerToEven_base(x); } #endif @@ -267,37 +263,25 @@ Ceil_32(float x) #else // Base implementation -inline int32_t -RoundHalfIntegerUp_32(double x) -{ - return RoundHalfIntegerUp_base(x); -} -inline int32_t -RoundHalfIntegerUp_32(float x) +template +constexpr int32_t +RoundHalfIntegerUp_32(TInput x) { - return RoundHalfIntegerUp_base(x); + return RoundHalfIntegerUp_base(x); } -inline int32_t -Floor_32(double x) -{ - return Floor_base(x); -} -inline int32_t -Floor_32(float x) +template +constexpr int32_t +Floor_32(TInput x) { - return Floor_base(x); + return Floor_base(x); } -inline int32_t -Ceil_32(double x) -{ - return Ceil_base(x); -} -inline int32_t -Ceil_32(float x) +template +constexpr int32_t +Ceil_32(TInput x) { - return Ceil_base(x); + return Ceil_base(x); } #endif // USE_SSE2_32IMPL || GCC_USE_ASM_32IMPL || VC_USE_ASM_32IMPL @@ -383,15 +367,11 @@ RoundHalfIntegerToEven_64(float x) #else // Base implementation -inline int64_t -RoundHalfIntegerToEven_64(double x) -{ - return RoundHalfIntegerToEven_base(x); -} -inline int64_t -RoundHalfIntegerToEven_64(float x) +template +constexpr int64_t +RoundHalfIntegerToEven_64(TInput x) { - return RoundHalfIntegerToEven_base(x); + return RoundHalfIntegerToEven_base(x); } #endif @@ -433,37 +413,25 @@ Ceil_64(float x) #else // Base implementation -inline int64_t -RoundHalfIntegerUp_64(double x) -{ - return RoundHalfIntegerUp_base(x); -} -inline int64_t -RoundHalfIntegerUp_64(float x) +template +constexpr int64_t +RoundHalfIntegerUp_64(TInput x) { - return RoundHalfIntegerUp_base(x); + return RoundHalfIntegerUp_base(x); } -inline int64_t -Floor_64(double x) -{ - return Floor_base(x); -} -inline int64_t -Floor_64(float x) +template +constexpr int64_t +Floor_64(TInput x) { - return Floor_base(x); + return Floor_base(x); } -inline int64_t -Ceil_64(double x) -{ - return Ceil_base(x); -} -inline int64_t -Ceil_64(float x) +template +constexpr int64_t +Ceil_64(TInput x) { - return Ceil_base(x); + return Ceil_base(x); } #endif // USE_SSE2_64IMPL || GCC_USE_ASM_64IMPL || VC_USE_ASM_64IMPL @@ -496,18 +464,21 @@ union FloatIEEE IntType asInt; UIntType asUInt; - FloatIEEE(FloatType f) + constexpr FloatIEEE(FloatType f) : asFloat(f) {} - FloatIEEE(IntType i) + constexpr FloatIEEE(IntType i) : asInt(i) {} - [[nodiscard]] bool + constexpr FloatIEEE(UIntType ui) + : asUInt(ui) + {} + [[nodiscard]] constexpr bool Sign() const { return (asUInt >> (sizeof(asUInt) * 8 - 1)) != 0; } - [[nodiscard]] IntType + [[nodiscard]] constexpr IntType AsULP() const { return this->Sign() ? IntType(~(~UIntType(0) >> 1) - asUInt) : asInt; diff --git a/Modules/Core/Common/src/CMakeLists.txt b/Modules/Core/Common/src/CMakeLists.txt index b7ad1e52486..59f4d0a2c9f 100644 --- a/Modules/Core/Common/src/CMakeLists.txt +++ b/Modules/Core/Common/src/CMakeLists.txt @@ -147,7 +147,6 @@ set( itkArrayOutputSpecialization.cxx itkNumberToString.cxx itkRandomVariateGeneratorBase.cxx - itkMath.cxx itkProgressTransformer.cxx itkSymmetricEigenAnalysis.cxx itkExtractImageFilter.cxx diff --git a/Modules/Core/Common/src/itkMath.cxx b/Modules/Core/Common/src/itkMath.cxx deleted file mode 100644 index 44d3aa63d75..00000000000 --- a/Modules/Core/Common/src/itkMath.cxx +++ /dev/null @@ -1,116 +0,0 @@ -/*========================================================================= - * - * Copyright NumFOCUS - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0.txt - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - *=========================================================================*/ -#include "itkMath.h" - -namespace itk::Math -{ - -namespace -{ - -template -inline bool -IsPrime(T n) -{ - if (n <= 1) - { - return false; - } - const auto last = (T)std::sqrt(static_cast(n)); - for (T x = 2; x <= last; ++x) - { - if (n % x == 0) - { - return false; - } - } - return true; -} - -template -inline T -GreatestPrimeFactor(T n) -{ - T v = 2; - while (v <= n) - { - if (n % v == 0 && IsPrime(v)) - { - n /= v; - } - else - { - v += 1; - } - } - return v; -} - -} // end anonymous namespace - - -bool -IsPrime(unsigned short n) -{ - return IsPrime(n); -} - -bool -IsPrime(unsigned int n) -{ - return IsPrime(n); -} - -bool -IsPrime(unsigned long n) -{ - return IsPrime(n); -} - -bool -IsPrime(unsigned long long n) -{ - return IsPrime(n); -} - - -unsigned short -GreatestPrimeFactor(unsigned short n) -{ - return GreatestPrimeFactor(n); -} - -unsigned int -GreatestPrimeFactor(unsigned int n) -{ - return GreatestPrimeFactor(n); -} - -unsigned long -GreatestPrimeFactor(unsigned long n) -{ - return GreatestPrimeFactor(n); -} - -unsigned long long -GreatestPrimeFactor(unsigned long long n) -{ - return GreatestPrimeFactor(n); -} - -} // namespace itk::Math diff --git a/Modules/Core/Common/test/CMakeLists.txt b/Modules/Core/Common/test/CMakeLists.txt index f196bb07bd3..64017632ff6 100644 --- a/Modules/Core/Common/test/CMakeLists.txt +++ b/Modules/Core/Common/test/CMakeLists.txt @@ -213,16 +213,6 @@ createtestdriver( set(BASELINE "${ITK_DATA_ROOT}/Baseline/Common") set(TEMP ${ITK_TEST_OUTPUT_DIR}) -add_executable(itkMathTest itkMathTest.cxx) -target_link_options( - itkMathTest - PRIVATE - "$<$,$,15.0>>:LINKER:-no_warn_duplicate_libraries>" -) -itk_module_target_label(itkMathTest) -target_link_libraries(itkMathTest PUBLIC ${ITKCommon-Test_LIBRARIES}) -itk_add_test(NAME itkMathTest COMMAND itkMathTest) - add_executable(itkSystemInformation itkSystemInformation.cxx) target_link_options( itkSystemInformation @@ -1906,6 +1896,7 @@ set( itkVectorGTest.cxx itkWeakPointerGTest.cxx itkCommonTypeTraitsGTest.cxx + itkMathGTest.cxx itkMetaDataDictionaryGTest.cxx itkSpatialOrientationAdaptorGTest.cxx itkAnatomicalOrientationGTest.cxx diff --git a/Modules/Core/Common/test/itkMathGTest.cxx b/Modules/Core/Common/test/itkMathGTest.cxx new file mode 100644 index 00000000000..c653dc3cf0a --- /dev/null +++ b/Modules/Core/Common/test/itkMathGTest.cxx @@ -0,0 +1,391 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ + +#if !defined(ITK_LEGACY_REMOVE) +// Suppress MSVC warnings from VS2022, saying: "warning C4996: 'std::complex::complex': warning STL4037: The effect +// of instantiating the template std::complex for any type other than float, double, or long double is unspecified." +# define _SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING +#endif + +#include "itkMath.h" +#include "itkGTest.h" +#include +#include + +namespace +{ + +constexpr auto maxUnsignedValue = std::numeric_limits::max(); + +using itk::Math::UnsignedPower; +using itk::Math::UnsignedProduct; + +static_assert((UnsignedPower(0, 1) == 0) && (UnsignedPower(0, 2) == 0) && (UnsignedPower(0, 3) == 0), + "Check powers of zero"); +static_assert((UnsignedPower(1, 0) == 1) && (UnsignedPower(1, 1) == 1) && (UnsignedPower(1, 2) == 1), + "Check powers of one"); +static_assert((UnsignedPower(2, 0) == 1) && (UnsignedPower(3, 0) == 1) && (UnsignedPower(maxUnsignedValue, 0) == 1), + "Check zero as exponent"); +static_assert((UnsignedPower(2, 1) == 2) && (UnsignedPower(3, 1) == 3) && + (UnsignedPower(maxUnsignedValue, 1) == maxUnsignedValue), + "Check one as exponent"); +static_assert((UnsignedPower(2, 2) == 4) && (UnsignedPower(2, 3) == 8), "Check powers of two"); +static_assert((UnsignedPower(3, 2) == 9) && (UnsignedPower(3, 3) == 27), "Check powers of three"); +static_assert(UnsignedPower(2, std::numeric_limits::digits - 1) == + (uintmax_t{ 1 } << (std::numeric_limits::digits - 1)), + "Check 2^63 (at least when uintmax_t is 64 bits)"); + +static_assert(std::is_same_v, + "The return type of UnsignedPower should be uintmax_t by default."); +static_assert(std::is_same_v(1, 1)), uint8_t> && + std::is_same_v(1, 1)), uint16_t> && + std::is_same_v(1, 1)), uint32_t>, + "UnsignedPower allows specifying the return type by its template argument."); + +static_assert((UnsignedProduct(0, 0) == 0) && (UnsignedProduct(0, 1) == 0) && (UnsignedProduct(1, 0) == 0) && + (UnsignedProduct(1, 1) == 1), + "Check all product combinations of zero and one"); +static_assert((UnsignedProduct(2, 3) == 6) && (UnsignedProduct(3, 2) == 6), "Check 2*3 and 3*2"); +static_assert((UnsignedProduct(1, maxUnsignedValue) == maxUnsignedValue) && + (UnsignedProduct(maxUnsignedValue, 1) == maxUnsignedValue), + "Check products with the maximum unsigned value"); + + +template +void +TestIntegersAreSame(const T1 & v1, const T2 & v2) +{ + EXPECT_EQ(static_cast(v1), v2) << v1 << " static_cast " << static_cast(v1) << " != " << v2; + EXPECT_FALSE(itk::Math::AlmostEquals(v2, v1)) + << "itk::Math::AlmostEquals(" << v2 << ", " << v1 << ") should be false"; + EXPECT_FALSE(itk::Math::AlmostEquals(v1, v2)) + << "itk::Math::AlmostEquals(" << v1 << ", " << v2 << ") should be false"; +} + + +template +void +ExerciseIsPrime() +{ + EXPECT_FALSE(itk::Math::IsPrime(static_cast(0))); + EXPECT_FALSE(itk::Math::IsPrime(static_cast(1))); + EXPECT_TRUE(itk::Math::IsPrime(static_cast(2))); + EXPECT_TRUE(itk::Math::IsPrime(static_cast(3))); + EXPECT_FALSE(itk::Math::IsPrime(static_cast(4))); + EXPECT_TRUE(itk::Math::IsPrime(static_cast(5))); + EXPECT_FALSE(itk::Math::IsPrime(static_cast(6))); + EXPECT_TRUE(itk::Math::IsPrime(static_cast(7))); + EXPECT_FALSE(itk::Math::IsPrime(static_cast(8))); + EXPECT_FALSE(itk::Math::IsPrime(static_cast(9))); + EXPECT_FALSE(itk::Math::IsPrime(static_cast(10))); + EXPECT_TRUE(itk::Math::IsPrime(static_cast(11))); + EXPECT_FALSE(itk::Math::IsPrime(static_cast(12))); + EXPECT_TRUE(itk::Math::IsPrime(static_cast(13))); +} + + +template +void +ExerciseGreatestPrimeFactor() +{ + EXPECT_EQ(itk::Math::GreatestPrimeFactor(static_cast(12)), 3u); + EXPECT_EQ(itk::Math::GreatestPrimeFactor(static_cast(75)), 5u); + EXPECT_EQ(itk::Math::GreatestPrimeFactor(static_cast(1024)), 2u); +} + +union FloatRepresentationF +{ + float asFloat; + itk::int32_t asInt; +}; + +union FloatRepresentationD +{ + double asFloat; + itk::int64_t asInt; +}; + +} // namespace + +TEST(itkMath, Constants) +{ + EXPECT_GT(itk::Math::e, 2.71); + EXPECT_GT(itk::Math::pi, 3.14); + // Just a simple consistency check as in the original test + double val = itk::Math::e * itk::Math::log2e * itk::Math::log10e * itk::Math::ln2 * itk::Math::pi * + itk::Math::pi_over_2 * itk::Math::pi_over_4 * itk::Math::one_over_pi * itk::Math::two_over_pi * + itk::Math::two_over_sqrtpi * itk::Math::one_over_sqrt2pi * itk::Math::sqrt2 * itk::Math::sqrt1_2; + EXPECT_GT(val, 0.0); +} + +TEST(itkMath, FloatAlmostEqual) +{ + FloatRepresentationF floatRepresentationfx1; + floatRepresentationfx1.asFloat = -1.0f; + + FloatRepresentationF floatRepresentationfx2; + floatRepresentationfx2.asFloat = itk::Math::FloatAddULP(floatRepresentationfx1.asFloat, -1); + EXPECT_EQ(itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat), -1); + EXPECT_TRUE(itk::Math::FloatAlmostEqual(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat)); + + floatRepresentationfx2.asFloat = itk::Math::FloatAddULP(floatRepresentationfx1.asFloat, 1); + EXPECT_EQ(itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat), 1); + EXPECT_TRUE(itk::Math::FloatAlmostEqual(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat)); + + floatRepresentationfx1.asFloat = 1.0f; + floatRepresentationfx2.asFloat = itk::Math::FloatAddULP(floatRepresentationfx1.asFloat, 1); + EXPECT_EQ(itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat), -1); + EXPECT_TRUE(itk::Math::FloatAlmostEqual(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat)); + + floatRepresentationfx2.asFloat = itk::Math::FloatAddULP(floatRepresentationfx1.asFloat, -1); + EXPECT_EQ(itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat), 1); + EXPECT_TRUE(itk::Math::FloatAlmostEqual(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat)); + + // The default maxUlps is 4, so this should not be considered almost equals. + floatRepresentationfx2.asFloat = itk::Math::FloatAddULP(floatRepresentationfx1.asFloat, 6); + EXPECT_EQ(itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat), -6); + EXPECT_FALSE(itk::Math::FloatAlmostEqual(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat)); + + floatRepresentationfx2.asFloat = itk::Math::FloatAddULP(floatRepresentationfx1.asFloat, -6); + EXPECT_EQ(itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat), 6); + EXPECT_FALSE(itk::Math::FloatAlmostEqual(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat)); + + floatRepresentationfx1.asFloat = -0.0f; + floatRepresentationfx2.asFloat = 0.0f; + EXPECT_EQ(itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat), 0); + EXPECT_TRUE(itk::Math::FloatAlmostEqual(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat)); + + floatRepresentationfx1.asFloat = 0.0f; + floatRepresentationfx2.asFloat = 67329.234f - 67329.242f; + EXPECT_TRUE(itk::Math::FloatAlmostEqual(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat, 4, 0.1f)); + + floatRepresentationfx1.asFloat = 1e-8f; + floatRepresentationfx2.asFloat = -1e-8f; + EXPECT_GE(itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat), 0); + + floatRepresentationfx1.asFloat = -1e-8f; + floatRepresentationfx2.asFloat = 1e-8f; + EXPECT_LE(itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat), 0); +} + +TEST(itkMath, DoubleAlmostEqual) +{ + FloatRepresentationD floatRepresentationdx1; + floatRepresentationdx1.asFloat = -1.0; + + FloatRepresentationD floatRepresentationdx2; + floatRepresentationdx2.asFloat = itk::Math::FloatAddULP(floatRepresentationdx1.asFloat, -1); + EXPECT_EQ(itk::Math::FloatDifferenceULP(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat), -1); + EXPECT_TRUE(itk::Math::FloatAlmostEqual(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat)); + + floatRepresentationdx2.asFloat = itk::Math::FloatAddULP(floatRepresentationdx1.asFloat, 1); + EXPECT_EQ(itk::Math::FloatDifferenceULP(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat), 1); + EXPECT_TRUE(itk::Math::FloatAlmostEqual(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat)); + + // The default maxUlps is 4, so this should not be considered almost equals. + floatRepresentationdx2.asFloat = itk::Math::FloatAddULP(floatRepresentationdx1.asFloat, -6); + EXPECT_EQ(itk::Math::FloatDifferenceULP(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat), -6); + EXPECT_FALSE(itk::Math::FloatAlmostEqual(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat)); + + floatRepresentationdx2.asFloat = itk::Math::FloatAddULP(floatRepresentationdx1.asFloat, 6); + EXPECT_EQ(itk::Math::FloatDifferenceULP(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat), 6); + EXPECT_FALSE(itk::Math::FloatAlmostEqual(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat)); + + floatRepresentationdx1.asFloat = -0.0; + floatRepresentationdx2.asFloat = 0.0; + EXPECT_EQ(itk::Math::FloatDifferenceULP(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat), 0); + EXPECT_TRUE(itk::Math::FloatAlmostEqual(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat)); + + floatRepresentationdx1.asFloat = 0.0; + floatRepresentationdx2.asFloat = 67329.234 - 67329.242; + EXPECT_TRUE(itk::Math::FloatAlmostEqual(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat, 4, 0.1)); + + floatRepresentationdx1.asFloat = 1e-8; + floatRepresentationdx2.asFloat = -1e-8; + EXPECT_GE(itk::Math::FloatDifferenceULP(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat), 0); + + floatRepresentationdx1.asFloat = -1e-8; + floatRepresentationdx2.asFloat = 1e-8; + EXPECT_LE(itk::Math::FloatDifferenceULP(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat), 0); +} + +TEST(itkMath, EqualsOperations) +{ + constexpr signed char sc{ -1 }; + constexpr auto uc = static_cast(-1); + TestIntegersAreSame(sc, uc); + + constexpr int si{ -1 }; + constexpr auto ul = static_cast(-1); + TestIntegersAreSame(si, ul); + + constexpr auto ui = static_cast(-1); + TestIntegersAreSame(si, ui); + + constexpr auto ust = static_cast(-1); + TestIntegersAreSame(si, ust); + + constexpr float f{ -1.0f }; + constexpr double d{ 1.01 }; + + EXPECT_FALSE(itk::Math::AlmostEquals(f, d)); + EXPECT_FALSE(itk::Math::AlmostEquals(d, f)); + EXPECT_TRUE(itk::Math::AlmostEquals(f, sc)); + EXPECT_TRUE(itk::Math::AlmostEquals(sc, f)); + EXPECT_TRUE(itk::Math::AlmostEquals(1.0, 1.0f)); + EXPECT_TRUE(itk::Math::AlmostEquals(1.1, 1.1f)); + EXPECT_TRUE(itk::Math::AlmostEquals(1, 1.0)); + EXPECT_FALSE(itk::Math::AlmostEquals(2.0, 1.0)); + EXPECT_FALSE(itk::Math::AlmostEquals(1, 2)); + + // ExactlyEquals constexpr tests + static_assert(!itk::Math::ExactlyEquals(f, d)); + static_assert(!itk::Math::ExactlyEquals(d, f)); + static_assert(!itk::Math::NotExactlyEquals(1.0f, 1.0)); + static_assert(!itk::Math::NotExactlyEquals(1.0, 1.0f)); + + FloatRepresentationD oneExact; + FloatRepresentationD oneAlmost; + oneExact.asFloat = 1.0; + oneAlmost.asFloat = 1.0; + oneAlmost.asInt += 1; + + EXPECT_TRUE(itk::Math::AlmostEquals(oneExact.asFloat, oneAlmost.asFloat)); + EXPECT_FALSE(itk::Math::ExactlyEquals(oneExact.asFloat, oneAlmost.asFloat)); + + // Complex comparisons + constexpr std::complex z1Double(1.1, 2.1); + constexpr std::complex z1Float(1.1f, 2.1f); + EXPECT_TRUE(itk::Math::AlmostEquals(z1Double, z1Float)); + +#if !defined(ITK_LEGACY_REMOVE) + constexpr std::complex z2Double(1.0, 3.0); + constexpr std::complex z2Int(1, 3); + EXPECT_TRUE(itk::Math::AlmostEquals(z2Double, z2Int)); +#endif + + FloatRepresentationD z1AlmostRealPart; + z1AlmostRealPart.asFloat = z1Double.real(); + z1AlmostRealPart.asInt += 1; + const std::complex z1DoubleAlmost(z1AlmostRealPart.asFloat, z1Double.imag()); + EXPECT_TRUE(itk::Math::AlmostEquals(z1Double, z1DoubleAlmost)); + + constexpr std::complex z3Double(0.123, 0); + constexpr float r3Float{ 0.123 }; + constexpr double r3Double{ 0.123 }; + EXPECT_TRUE(itk::Math::AlmostEquals(z3Double, r3Double)); + EXPECT_TRUE(itk::Math::AlmostEquals(z3Double, r3Float)); + + constexpr std::complex z4Float(0.123, 0); + FloatRepresentationF r4FloatAlmost; + r4FloatAlmost.asFloat = z4Float.real(); + r4FloatAlmost.asInt += 1; + EXPECT_TRUE(itk::Math::AlmostEquals(z4Float, r4FloatAlmost.asFloat)); + EXPECT_TRUE(itk::Math::AlmostEquals(z3Double, r4FloatAlmost.asFloat)); +} + +TEST(itkMath, IsPrime) +{ + ExerciseIsPrime(); + ExerciseIsPrime(); + ExerciseIsPrime(); + ExerciseIsPrime(); +} + +TEST(itkMath, GreatestPrimeFactor) +{ + ExerciseGreatestPrimeFactor(); + ExerciseGreatestPrimeFactor(); + ExerciseGreatestPrimeFactor(); + ExerciseGreatestPrimeFactor(); +} + +TEST(itkMath, Abs) +{ + // static_assert tests from an original file + static_assert(itk::Math::safe_abs(false) == false); + static_assert(itk::Math::safe_abs(true) == true); + static_assert(itk::Math::safe_abs(static_cast(5)) == 5); + static_assert(itk::Math::safe_abs(static_cast(5)) == 5); + static_assert(itk::Math::safe_abs(static_cast(5)) == 5); + static_assert(itk::Math::safe_abs(static_cast(5)) == 5); + static_assert(itk::Math::safe_abs(static_cast(5)) == 5); + static_assert(itk::Math::safe_abs(static_cast(-5)) == 5); + static_assert(itk::Math::safe_abs(static_cast(-128)) == 128); + static_assert(itk::Math::safe_abs(static_cast(-5)) == 5); + static_assert(itk::Math::safe_abs(-5) == 5u); + static_assert(itk::Math::safe_abs(-5L) == 5ul); + static_assert(itk::Math::safe_abs(-5LL) == 5ull); + static_assert(itk::Math::safe_abs(-5.0) == 5.0); + static_assert(itk::Math::safe_abs(-5.0f) == 5.0f); + + constexpr auto cf = std::complex(-3, -4); + EXPECT_EQ(itk::Math::safe_abs(cf), 5); + constexpr auto cd = std::complex(-3, -4); + EXPECT_EQ(itk::Math::safe_abs(cd), 5); + constexpr auto cld = std::complex(-3, -4); + EXPECT_EQ(itk::Math::safe_abs(cld), 5); + + EXPECT_EQ(itk::Math::abs(false), false); + EXPECT_EQ(itk::Math::abs(true), true); + EXPECT_EQ(itk::Math::abs(static_cast(5)), 5); + EXPECT_EQ(itk::Math::abs(static_cast(-5)), 5); + EXPECT_EQ(itk::Math::abs(static_cast(-128)), 128); + EXPECT_EQ(itk::Math::abs(static_cast(-5)), 5); + EXPECT_EQ(itk::Math::abs(-5), 5u); + EXPECT_EQ(itk::Math::abs(-5L), 5ul); + EXPECT_EQ(itk::Math::abs(-5LL), 5ull); + EXPECT_EQ(itk::Math::abs(-5.0), 5.0); + EXPECT_EQ(itk::Math::abs(-5.0f), 5.0f); + EXPECT_EQ(itk::Math::abs(-5), 5); +} + +TEST(itkMath, ConstexprTests) +{ + static_assert(itk::Math::ExactlyEquals(5, 5)); + static_assert(itk::Math::NotExactlyEquals(5, 6)); + static_assert(itk::Math::IsPrime(2)); + static_assert(itk::Math::IsPrime(3)); + static_assert(!itk::Math::IsPrime(4)); + static_assert(itk::Math::IsPrime(7)); + static_assert(itk::Math::IsPrime(97)); + static_assert(!itk::Math::IsPrime(100)); + static_assert(!itk::Math::IsPrime(1)); + static_assert(itk::Math::IsPrime(4294967291), "Failed on the largest uint32_t IsPrime computation"); + static_assert(itk::Math::GreatestPrimeFactor(10) == 5); + static_assert(itk::Math::GreatestPrimeFactor(13) == 13); + +#if !defined(WIN32) && __cplusplus >= 202302L + static_assert(itk::Math::Round(1.5) == 2); + static_assert(itk::Math::Round(2.5) == 3); + static_assert(itk::Math::Floor(1.9) == 1); + static_assert(itk::Math::Floor(-1.1) == -2); + static_assert(itk::Math::Ceil(1.1) == 2); + static_assert(itk::Math::Ceil(-1.9) == -1); +#endif +} + +TEST(itkMath, RoundFloorCeil) +{ + EXPECT_EQ(itk::Math::Round(1.5), 2); + EXPECT_EQ(itk::Math::Round(2.5), 3); + EXPECT_EQ(itk::Math::Floor(1.9), 1); + EXPECT_EQ(itk::Math::Floor(-1.1), -2); + EXPECT_EQ(itk::Math::Ceil(1.1), 2); + EXPECT_EQ(itk::Math::Ceil(-1.9), -1); +} diff --git a/Modules/Core/Common/test/itkMathTest.cxx b/Modules/Core/Common/test/itkMathTest.cxx deleted file mode 100644 index c280c865764..00000000000 --- a/Modules/Core/Common/test/itkMathTest.cxx +++ /dev/null @@ -1,917 +0,0 @@ -/*========================================================================= - * - * Copyright NumFOCUS - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0.txt - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - *=========================================================================*/ - -#if !defined(ITK_LEGACY_REMOVE) -// Suppress MSVC warnings from VS2022, saying: "warning C4996: 'std::complex::complex': warning STL4037: The effect -// of instantiating the template std::complex for any type other than float, double, or long double is unspecified." -# define _SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING -#endif - -#include "itkMath.h" -#include "itkIntTypes.h" -#include "itkStdStreamStateSave.h" -#include "itkTestingMacros.h" - -#include -#include -#include // For is_same. - -constexpr auto maxUnsignedValue = std::numeric_limits::max(); - -using itk::Math::UnsignedPower; -using itk::Math::UnsignedProduct; - -static_assert((UnsignedPower(0, 1) == 0) && (UnsignedPower(0, 2) == 0) && (UnsignedPower(0, 3) == 0), - "Check powers of zero"); -static_assert((UnsignedPower(1, 0) == 1) && (UnsignedPower(1, 1) == 1) && (UnsignedPower(1, 2) == 1), - "Check powers of one"); -static_assert((UnsignedPower(2, 0) == 1) && (UnsignedPower(3, 0) == 1) && (UnsignedPower(maxUnsignedValue, 0) == 1), - "Check zero as exponent"); -static_assert((UnsignedPower(2, 1) == 2) && (UnsignedPower(3, 1) == 3) && - (UnsignedPower(maxUnsignedValue, 1) == maxUnsignedValue), - "Check one as exponent"); -static_assert((UnsignedPower(2, 2) == 4) && (UnsignedPower(2, 3) == 8), "Check powers of two"); -static_assert((UnsignedPower(3, 2) == 9) && (UnsignedPower(3, 3) == 27), "Check powers of three"); -static_assert(UnsignedPower(2, std::numeric_limits::digits - 1) == - (uintmax_t{ 1 } << (std::numeric_limits::digits - 1)), - "Check 2^63 (at least when uintmax_t is 64 bits)"); - -static_assert(std::is_same_v, - "The return type of UnsignedPower should be uintmax_t by default."); -static_assert(std::is_same_v(1, 1)), uint8_t> && - std::is_same_v(1, 1)), uint16_t> && - std::is_same_v(1, 1)), uint32_t>, - "UnsignedPower allows specifying the return type by its template argument."); - -static_assert((UnsignedProduct(0, 0) == 0) && (UnsignedProduct(0, 1) == 0) && (UnsignedProduct(1, 0) == 0) && - (UnsignedProduct(1, 1) == 1), - "Check all product combinations of zero and one"); -static_assert((UnsignedProduct(2, 3) == 6) && (UnsignedProduct(3, 2) == 6), "Check 2*3 and 3*2"); -static_assert((UnsignedProduct(1, maxUnsignedValue) == maxUnsignedValue) && - (UnsignedProduct(maxUnsignedValue, 1) == maxUnsignedValue), - "Check products with the maximum unsigned value"); - - -template -inline int -TestIntegersAreSame(const T1 & v1, const T2 & v2) -{ - int testPassStatus = EXIT_SUCCESS; - if (static_cast(v1) != v2) - { - std::cout << "ERROR: static cast did not perform as expected for wrap around." << std::endl; - std::cout << v1 << " static_cast " << static_cast(v1) << std::endl; - std::cout << v2 << std::endl; - testPassStatus = EXIT_FAILURE; - } - if (itk::Math::AlmostEquals(v2, v1)) - { - std::cout << "Error in " - << "itk::Math::AlmostEquals(v2, v1) " << std::endl; - std::cout << __FILE__ << ' ' << __LINE__ << ' ' << v2 << " == " << v1 << std::endl; - testPassStatus = EXIT_FAILURE; - } - if (itk::Math::AlmostEquals(v1, v2)) - { - std::cout << "Error in " - << "itk::Math::AlmostEquals(v1, v2) " << std::endl; - std::cout << __FILE__ << ' ' << __LINE__ << ' ' << v1 << " == " << v2 << std::endl; - testPassStatus = EXIT_FAILURE; - } - return testPassStatus; -} - - -template -int -ExerciseIsPrime() -{ - int testPassStatus = EXIT_SUCCESS; - - ITK_TEST_EXPECT_TRUE_STATUS_VALUE((itk::Math::IsPrime(static_cast(0)) == false), testPassStatus); - ITK_TEST_EXPECT_TRUE_STATUS_VALUE((itk::Math::IsPrime(static_cast(1)) == false), testPassStatus); - ITK_TEST_EXPECT_TRUE_STATUS_VALUE((itk::Math::IsPrime(static_cast(2))), testPassStatus); - ITK_TEST_EXPECT_TRUE_STATUS_VALUE((itk::Math::IsPrime(static_cast(3))), testPassStatus); - ITK_TEST_EXPECT_TRUE_STATUS_VALUE((itk::Math::IsPrime(static_cast(4)) == false), testPassStatus); - ITK_TEST_EXPECT_TRUE_STATUS_VALUE((itk::Math::IsPrime(static_cast(5))), testPassStatus); - ITK_TEST_EXPECT_TRUE_STATUS_VALUE((itk::Math::IsPrime(static_cast(6)) == false), testPassStatus); - ITK_TEST_EXPECT_TRUE_STATUS_VALUE((itk::Math::IsPrime(static_cast(7))), testPassStatus); - ITK_TEST_EXPECT_TRUE_STATUS_VALUE((itk::Math::IsPrime(static_cast(8)) == false), testPassStatus); - ITK_TEST_EXPECT_TRUE_STATUS_VALUE((itk::Math::IsPrime(static_cast(9)) == false), testPassStatus); - ITK_TEST_EXPECT_TRUE_STATUS_VALUE((itk::Math::IsPrime(static_cast(10)) == false), testPassStatus); - ITK_TEST_EXPECT_TRUE_STATUS_VALUE((itk::Math::IsPrime(static_cast(11))), testPassStatus); - ITK_TEST_EXPECT_TRUE_STATUS_VALUE((itk::Math::IsPrime(static_cast(12)) == false), testPassStatus); - ITK_TEST_EXPECT_TRUE_STATUS_VALUE((itk::Math::IsPrime(static_cast(13))), testPassStatus); - - return testPassStatus; -} - - -template -int -ExerciseGreatestPrimeFactor() -{ - int testPassStatus = EXIT_SUCCESS; - - ITK_TEST_EXPECT_EQUAL_STATUS_VALUE(itk::Math::GreatestPrimeFactor(static_cast(12)), 3, testPassStatus); - ITK_TEST_EXPECT_EQUAL_STATUS_VALUE(itk::Math::GreatestPrimeFactor(static_cast(75)), 5, testPassStatus); - ITK_TEST_EXPECT_EQUAL_STATUS_VALUE(itk::Math::GreatestPrimeFactor(static_cast(1024)), 2, testPassStatus); - - return testPassStatus; -} - - -int -main(int, char *[]) -{ - int testPassStatus = EXIT_SUCCESS; - - // Save the format stream variables for std::cout - // They will be restored when coutState goes out of scope - // scope. - const itk::StdStreamStateSave coutState(std::cout); - - std::cout << "e: " << itk::Math::e << std::endl; - std::cout << "log2e: " << itk::Math::log2e << std::endl; - std::cout << "log10e: " << itk::Math::log10e << std::endl; - std::cout << "ln2: " << itk::Math::ln2 << std::endl; - std::cout << "pi: " << itk::Math::pi << std::endl; - std::cout << "pi_over_2: " << itk::Math::pi_over_2 << std::endl; - std::cout << "two_over_pi: " << itk::Math::two_over_pi << std::endl; - std::cout << "two_over_sqrtpi: " << itk::Math::two_over_sqrtpi << std::endl; - std::cout << "one_over_sqrt2pi: " << itk::Math::one_over_sqrt2pi << std::endl; - std::cout << "sqrt2: " << itk::Math::sqrt2 << std::endl; - std::cout << "sqrt1_2: " << itk::Math::sqrt1_2 << std::endl; - - - std::cout << itk::Math::e * itk::Math::log2e * itk::Math::log10e * itk::Math::ln2 * itk::Math::pi * - itk::Math::pi_over_2 * itk::Math::pi_over_4 * itk::Math::one_over_pi * itk::Math::two_over_pi * - itk::Math::two_over_sqrtpi * itk::Math::one_over_sqrt2pi * itk::Math::sqrt2 * itk::Math::sqrt1_2 - << std::endl; - - - std::cout << "Testing itk::Math::FloatAlmostEqual" << std::endl; - union FloatRepresentationF - { - float asFloat; - itk::int32_t asInt; - }; - - FloatRepresentationF floatRepresentationfx1; - floatRepresentationfx1.asFloat = -1.0f; - std::cout << "floatRepresentationfx1.asFloat: " << floatRepresentationfx1.asFloat << std::endl; - std::cout << "floatRepresentationfx1.asInt: " << floatRepresentationfx1.asInt << std::endl; - - FloatRepresentationF floatRepresentationfx2; - floatRepresentationfx2.asFloat = itk::Math::FloatAddULP(floatRepresentationfx1.asFloat, -1); - // floatRepresentationfx2.asInt -= 1; // makes it 1 *higher* because it is a negative sign-magnitude integer! - std::cout << "floatRepresentationfx2.asFloat: " << floatRepresentationfx2.asFloat << std::endl; - std::cout << "floatRepresentationfx2.asInt: " << floatRepresentationfx2.asInt << std::endl; - std::cout << "Distance: " - << itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat) - << std::endl; - - if (itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat) != -1) - { - std::cout << "Unexpected float distance." << std::endl; - testPassStatus = EXIT_FAILURE; - } - if (itk::Math::FloatAlmostEqual(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat)) - { - std::cout << "floatRepresentationfx1 is almost equal to floatRepresentationfx2\n" << std::endl; - } - else - { - std::cout << "floatRepresentationfx1 is NOT almost equal to floatRepresentationfx2\n" << std::endl; - testPassStatus = EXIT_FAILURE; - } - - floatRepresentationfx2.asFloat = itk::Math::FloatAddULP(floatRepresentationfx1.asFloat, 1); - // floatRepresentationfx2.asInt += 1; // makes it 1 *lower* because it is a negative sign-magnitude integer! - std::cout << "floatRepresentationfx2.asFloat: " << floatRepresentationfx2.asFloat << std::endl; - std::cout << "floatRepresentationfx2.asInt: " << floatRepresentationfx2.asInt << std::endl; - std::cout << "Distance: " - << itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat) - << std::endl; - - if (itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat) != 1) - { - std::cout << "Unexpected float distance." << std::endl; - testPassStatus = EXIT_FAILURE; - } - if (itk::Math::FloatAlmostEqual(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat)) - { - std::cout << "floatRepresentationfx1 is almost equal to floatRepresentationfx2\n" << std::endl; - } - else - { - std::cout << "floatRepresentationfx1 is NOT almost equal to floatRepresentationfx2\n" << std::endl; - testPassStatus = EXIT_FAILURE; - } - - floatRepresentationfx1.asFloat = 1.0f; - std::cout << "floatRepresentationfx1.asFloat: " << floatRepresentationfx1.asFloat << std::endl; - std::cout << "floatRepresentationfx1.asInt: " << floatRepresentationfx1.asInt << std::endl; - - floatRepresentationfx2.asFloat = itk::Math::FloatAddULP(floatRepresentationfx1.asFloat, 1); - std::cout << "floatRepresentationfx2.asFloat: " << floatRepresentationfx2.asFloat << std::endl; - std::cout << "floatRepresentationfx2.asInt: " << floatRepresentationfx2.asInt << std::endl; - std::cout << "Distance: " - << itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat) - << std::endl; - - if (itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat) != -1) - { - std::cout << " result is: " - << itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat) - << std::endl; - std::cout << "Unexpected float distance." << std::endl; - testPassStatus = EXIT_FAILURE; - } - if (itk::Math::FloatAlmostEqual(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat)) - { - std::cout << "floatRepresentationfx1 is almost equal to floatRepresentationfx2\n" << std::endl; - } - else - { - std::cout << "floatRepresentationfx1 is NOT almost equal to floatRepresentationfx2\n" << std::endl; - testPassStatus = EXIT_FAILURE; - } - - floatRepresentationfx2.asFloat = itk::Math::FloatAddULP(floatRepresentationfx1.asFloat, -1); - std::cout << "floatRepresentationfx2.asFloat: " << floatRepresentationfx2.asFloat << std::endl; - std::cout << "floatRepresentationfx2.asInt: " << floatRepresentationfx2.asInt << std::endl; - std::cout << "Distance: " - << itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat) - << std::endl; - - if (itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat) != 1) - { - std::cout << "Unexpected float distance." << std::endl; - testPassStatus = EXIT_FAILURE; - } - if (itk::Math::FloatAlmostEqual(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat)) - { - std::cout << "floatRepresentationfx1 is almost equal to floatRepresentationfx2\n" << std::endl; - } - else - { - std::cout << "floatRepresentationfx1 is NOT almost equal to floatRepresentationfx2\n" << std::endl; - testPassStatus = EXIT_FAILURE; - } - - // The default maxUlps is 4, so this should not be considered almost equals. - floatRepresentationfx2.asFloat = itk::Math::FloatAddULP(floatRepresentationfx1.asFloat, 6); - std::cout << "floatRepresentationfx2.asFloat: " << floatRepresentationfx2.asFloat << std::endl; - std::cout << "floatRepresentationfx2.asInt: " << floatRepresentationfx2.asInt << std::endl; - std::cout << "Distance: " - << itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat) - << std::endl; - - if (itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat) != -6) - { - std::cout << "Unexpected float distance." << std::endl; - testPassStatus = EXIT_FAILURE; - } - if (itk::Math::FloatAlmostEqual(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat)) - { - std::cout << "floatRepresentationfx1 is almost equal to floatRepresentationfx2\n" << std::endl; - testPassStatus = EXIT_FAILURE; - } - else - { - std::cout << "floatRepresentationfx1 is NOT almost equal to floatRepresentationfx2\n" << std::endl; - } - - floatRepresentationfx2.asFloat = itk::Math::FloatAddULP(floatRepresentationfx1.asFloat, -6); - std::cout << "floatRepresentationfx2.asFloat: " << floatRepresentationfx2.asFloat << std::endl; - std::cout << "floatRepresentationfx2.asInt: " << floatRepresentationfx2.asInt << std::endl; - std::cout << "Distance: " - << itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat) - << std::endl; - - if (itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat) != 6) - { - std::cout << "Unexpected float distance." << std::endl; - testPassStatus = EXIT_FAILURE; - } - if (itk::Math::FloatAlmostEqual(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat)) - { - std::cout << "floatRepresentationfx1 is almost equal to floatRepresentationfx2\n" << std::endl; - testPassStatus = EXIT_FAILURE; - } - else - { - std::cout << "floatRepresentationfx1 is NOT almost equal to floatRepresentationfx2\n" << std::endl; - } - - floatRepresentationfx1.asFloat = -0.0f; - std::cout << "floatRepresentationfx1.asFloat: " << floatRepresentationfx1.asFloat << std::endl; - std::cout << "floatRepresentationfx1.asInt: " << floatRepresentationfx1.asInt << std::endl; - floatRepresentationfx2.asFloat = 0.0f; - std::cout << "floatRepresentationfx2.asFloat: " << floatRepresentationfx2.asFloat << std::endl; - std::cout << "floatRepresentationfx2.asInt: " << floatRepresentationfx2.asInt << std::endl; - std::cout << "Distance: " - << itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat) - << std::endl; - - if (itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat) != 0) - { - std::cout << "Unexpected float distance." << std::endl; - testPassStatus = EXIT_FAILURE; - } - if (itk::Math::FloatAlmostEqual(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat)) - { - std::cout << "floatRepresentationfx1 is almost equal to floatRepresentationfx2\n" << std::endl; - } - else - { - std::cout << "floatRepresentationfx1 is NOT almost equal to floatRepresentationfx2\n" << std::endl; - testPassStatus = EXIT_FAILURE; - } - - floatRepresentationfx1.asFloat = 0.0f; - std::cout << "floatRepresentationfx1.asFloat: " << floatRepresentationfx1.asFloat << std::endl; - std::cout << "floatRepresentationfx1.asInt: " << floatRepresentationfx1.asInt << std::endl; - // Bad -- should not do this -- we should call FloatAlmostEqual on the numbers - // directly. As a result of our naughtiness, the maxAbsoluteDifference - // tolerance has to be increased for the comparison to work. Now our - // comparison is dependent on the magnitude of the values. - floatRepresentationfx2.asFloat = 67329.234f - 67329.242f; - std::cout << "floatRepresentationfx2.asFloat: " << floatRepresentationfx2.asFloat << std::endl; - std::cout << "floatRepresentationfx2.asInt: " << floatRepresentationfx2.asInt << std::endl; - std::cout << "Distance: " - << itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat) - << std::endl; - - if (itk::Math::FloatAlmostEqual(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat, 4, 0.1f)) - { - std::cout << "floatRepresentationfx1 is almost equal to floatRepresentationfx2\n" << std::endl; - } - else - { - std::cout << "floatRepresentationfx1 is NOT almost equal to floatRepresentationfx2\n" << std::endl; - testPassStatus = EXIT_FAILURE; - } - - floatRepresentationfx1.asFloat = 1e-8f; - std::cout << "floatRepresentationfx1.asFloat: " << floatRepresentationfx1.asFloat << std::endl; - std::cout << "floatRepresentationfx1.asInt: " << floatRepresentationfx1.asInt << std::endl; - floatRepresentationfx2.asFloat = -1e-8f; - std::cout << "floatRepresentationfx2.asFloat: " << floatRepresentationfx2.asFloat << std::endl; - std::cout << "floatRepresentationfx2.asInt: " << floatRepresentationfx2.asInt << std::endl; - std::cout << "Distance: " - << itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat) - << std::endl; - - if (itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat) < 0) - { - std::cout << "Did not get the expected FloatDifferenceULP sign." << std::endl; - testPassStatus = EXIT_FAILURE; - } - else - { - std::cout << "Got the expected FloatDifferenceULP sign.\n" << std::endl; - } - - floatRepresentationfx1.asFloat = -1e-8f; - std::cout << "floatRepresentationfx1.asFloat: " << floatRepresentationfx1.asFloat << std::endl; - std::cout << "floatRepresentationfx1.asInt: " << floatRepresentationfx1.asInt << std::endl; - floatRepresentationfx2.asFloat = 1e-8f; - std::cout << "floatRepresentationfx2.asFloat: " << floatRepresentationfx2.asFloat << std::endl; - std::cout << "floatRepresentationfx2.asInt: " << floatRepresentationfx2.asInt << std::endl; - std::cout << "Distance: " - << itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat) - << std::endl; - - if (itk::Math::FloatDifferenceULP(floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat) > 0) - { - std::cout << "Did not get the expected FloatDifferenceULP sign." << std::endl; - testPassStatus = EXIT_FAILURE; - } - else - { - std::cout << "Got the expected FloatDifferenceULP sign.\n" << std::endl; - } - - union FloatRepresentationD - { - double asFloat; - itk::int64_t asInt; - }; - - FloatRepresentationF floatRepresentationdx1; - floatRepresentationdx1.asFloat = -1.0; - std::cout << "floatRepresentationdx1.asFloat: " << floatRepresentationdx1.asFloat << std::endl; - std::cout << "floatRepresentationdx1.asInt: " << floatRepresentationdx1.asInt << std::endl; - - FloatRepresentationF floatRepresentationdx2; - floatRepresentationdx2.asFloat = itk::Math::FloatAddULP(floatRepresentationdx1.asFloat, -1); - // floatRepresentationdx2.asInt -= 1; // makes it 1 *higher* because it is a negative sign-magnitude integer! - - std::cout << "floatRepresentationdx2.asFloat: " << floatRepresentationdx2.asFloat << std::endl; - std::cout << "floatRepresentationdx2.asInt: " << floatRepresentationdx2.asInt << std::endl; - - if (itk::Math::FloatDifferenceULP(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat) != -1) - { - std::cout << "Unexpected float distance." << std::endl; - testPassStatus = EXIT_FAILURE; - } - if (itk::Math::FloatAlmostEqual(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat)) - { - std::cout << "floatRepresentationdx1 is almost equal to floatRepresentationdx2\n" << std::endl; - } - else - { - std::cout << "floatRepresentationdx1 is NOT almost equal to floatRepresentationdx2\n" << std::endl; - testPassStatus = EXIT_FAILURE; - } - - floatRepresentationdx2.asFloat = itk::Math::FloatAddULP(floatRepresentationdx1.asFloat, 1); - // floatRepresentationdx2.asInt += 1; // makes it 1 *lower* because it is a negative sign-magnitude integer! - std::cout << "floatRepresentationdx2.asFloat: " << floatRepresentationdx2.asFloat << std::endl; - std::cout << "floatRepresentationdx2.asInt: " << floatRepresentationdx2.asInt << std::endl; - - if (itk::Math::FloatDifferenceULP(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat) != 1) - { - std::cout << "Unexpected float distance." << std::endl; - testPassStatus = EXIT_FAILURE; - } - if (itk::Math::FloatAlmostEqual(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat)) - { - std::cout << "floatRepresentationdx1 is almost equal to floatRepresentationdx2\n" << std::endl; - } - else - { - std::cout << "floatRepresentationdx1 is NOT almost equal to floatRepresentationdx2\n" << std::endl; - testPassStatus = EXIT_FAILURE; - } - - // The default maxUlps is 4, so this should not be considered almost equals. - floatRepresentationdx2.asFloat = itk::Math::FloatAddULP(floatRepresentationdx1.asFloat, -6); - // floatRepresentationdx2.asInt -= 6; // makes it 6 *higher* because it is a negative sign-magnitude integer! - std::cout << "floatRepresentationdx2.asFloat: " << floatRepresentationdx2.asFloat << std::endl; - std::cout << "floatRepresentationdx2.asInt: " << floatRepresentationdx2.asInt << std::endl; - - if (itk::Math::FloatDifferenceULP(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat) != -6) - { - std::cout << "Unexpected float distance." << std::endl; - testPassStatus = EXIT_FAILURE; - } - if (itk::Math::FloatAlmostEqual(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat)) - { - std::cout << "floatRepresentationdx1 is almost equal to floatRepresentationdx2\n" << std::endl; - testPassStatus = EXIT_FAILURE; - } - else - { - std::cout << "floatRepresentationdx1 is NOT almost equal to floatRepresentationdx2\n" << std::endl; - } - - floatRepresentationdx2.asFloat = itk::Math::FloatAddULP(floatRepresentationdx1.asFloat, 6); - // floatRepresentationdx2.asInt += 6; // makes it 6 *lower* because it is a negative sign-magnitude integer! - std::cout << "floatRepresentationdx2.asFloat: " << floatRepresentationdx2.asFloat << std::endl; - std::cout << "floatRepresentationdx2.asInt: " << floatRepresentationdx2.asInt << std::endl; - - if (itk::Math::FloatDifferenceULP(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat) != 6) - { - std::cout << "Unexpected float distance." << std::endl; - testPassStatus = EXIT_FAILURE; - } - if (itk::Math::FloatAlmostEqual(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat)) - { - std::cout << "floatRepresentationdx1 is almost equal to floatRepresentationdx2\n" << std::endl; - testPassStatus = EXIT_FAILURE; - } - else - { - std::cout << "floatRepresentationdx1 is NOT almost equal to floatRepresentationdx2\n" << std::endl; - } - - floatRepresentationdx1.asFloat = -0.0; - std::cout << "floatRepresentationdx1.asFloat: " << floatRepresentationdx1.asFloat << std::endl; - std::cout << "floatRepresentationdx1.asInt: " << floatRepresentationdx1.asInt << std::endl; - floatRepresentationdx2.asFloat = 0.0; - std::cout << "floatRepresentationdx2.asFloat: " << floatRepresentationdx2.asFloat << std::endl; - std::cout << "floatRepresentationdx2.asInt: " << floatRepresentationdx2.asInt << std::endl; - - if (itk::Math::FloatDifferenceULP(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat) != 0) - { - std::cout << "Unexpected float distance." << std::endl; - testPassStatus = EXIT_FAILURE; - } - if (itk::Math::FloatAlmostEqual(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat)) - { - std::cout << "floatRepresentationdx1 is almost equal to floatRepresentationdx2\n" << std::endl; - } - else - { - std::cout << "floatRepresentationdx1 is NOT almost equal to floatRepresentationdx2\n" << std::endl; - testPassStatus = EXIT_FAILURE; - } - - floatRepresentationdx1.asFloat = 0.0; - std::cout << "floatRepresentationdx1.asFloat: " << floatRepresentationdx1.asFloat << std::endl; - std::cout << "floatRepresentationdx1.asInt: " << floatRepresentationdx1.asInt << std::endl; - // Bad -- should not do this -- we should call FloatAlmostEqual on the numbers - // directly. As a result of our naughtiness, the maxAbsoluteDifference - // tolerance has to be increased for the comparison to work. Now our - // comparison is dependent on the magnitude of the values. - floatRepresentationdx2.asFloat = 67329.234f - 67329.242f; - std::cout << "floatRepresentationdx2.asFloat: " << floatRepresentationdx2.asFloat << std::endl; - std::cout << "floatRepresentationdx2.asInt: " << floatRepresentationdx2.asInt << std::endl; - if (itk::Math::FloatAlmostEqual(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat, 4, 0.1f)) - { - std::cout << "floatRepresentationdx1 is almost equal to floatRepresentationdx2\n" << std::endl; - } - else - { - std::cout << "floatRepresentationdx1 is NOT almost equal to floatRepresentationdx2\n" << std::endl; - testPassStatus = EXIT_FAILURE; - } - - floatRepresentationdx1.asFloat = 1e-8f; - std::cout << "floatRepresentationdx1.asFloat: " << floatRepresentationdx1.asFloat << std::endl; - std::cout << "floatRepresentationdx1.asInt: " << floatRepresentationdx1.asInt << std::endl; - floatRepresentationdx2.asFloat = -1e-8f; - std::cout << "floatRepresentationdx2.asFloat: " << floatRepresentationdx2.asFloat << std::endl; - std::cout << "floatRepresentationdx2.asInt: " << floatRepresentationdx2.asInt << std::endl; - std::cout << "Distance: " - << itk::Math::FloatDifferenceULP(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat) - << std::endl; - - if (itk::Math::FloatDifferenceULP(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat) < 0) - { - std::cout << "Did not get the expected FloatDifferenceULP sign." << std::endl; - testPassStatus = EXIT_FAILURE; - } - else - { - std::cout << "Got the expected FloatDifferenceULP sign.\n" << std::endl; - } - - floatRepresentationdx1.asFloat = -1e-8f; - std::cout << "floatRepresentationdx1.asFloat: " << floatRepresentationdx1.asFloat << std::endl; - std::cout << "floatRepresentationdx1.asInt: " << floatRepresentationdx1.asInt << std::endl; - floatRepresentationdx2.asFloat = 1e-8f; - std::cout << "floatRepresentationdx2.asFloat: " << floatRepresentationdx2.asFloat << std::endl; - std::cout << "floatRepresentationdx2.asInt: " << floatRepresentationdx2.asInt << std::endl; - std::cout << "Distance: " - << itk::Math::FloatDifferenceULP(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat) - << std::endl; - - if (itk::Math::FloatDifferenceULP(floatRepresentationdx1.asFloat, floatRepresentationdx2.asFloat) > 0) - { - std::cout << "Did not get the expected FloatDifferenceULP sign." << std::endl; - testPassStatus = EXIT_FAILURE; - } - else - { - std::cout << "Got the expected FloatDifferenceULP sign.\n" << std::endl; - } - - { // Test various equals operations. - //========================= - constexpr signed char sc{ -1 }; - constexpr auto uc = static_cast(-1); - testPassStatus = (TestIntegersAreSame(sc, uc) == EXIT_SUCCESS) ? testPassStatus : EXIT_FAILURE; - //========================= - constexpr int si{ -1 }; - constexpr auto ul = static_cast(-1); - testPassStatus = (TestIntegersAreSame(si, ul) == EXIT_SUCCESS) ? testPassStatus : EXIT_FAILURE; - //========================= - constexpr auto ui = static_cast(-1); - testPassStatus = (TestIntegersAreSame(si, ui) == EXIT_SUCCESS) ? testPassStatus : EXIT_FAILURE; - //========================= - constexpr auto ust = static_cast(-1); - testPassStatus = (TestIntegersAreSame(si, ust) == EXIT_SUCCESS) ? testPassStatus : EXIT_FAILURE; - - //========================= - constexpr float f{ -1.0f }; - constexpr double d{ 1.01 }; - - // Test AlmostEquals() - if (itk::Math::AlmostEquals(f, d) || itk::Math::AlmostEquals(d, f)) - { - std::cout << __FILE__ << ' ' << __LINE__ << ' ' << f << " == " << d << std::endl; - testPassStatus = EXIT_FAILURE; - } - if (itk::Math::AlmostEquals(f, sc) == false || itk::Math::AlmostEquals(sc, f) == false || - itk::Math::AlmostEquals(1.0, 1.0f) == false || itk::Math::AlmostEquals(1.1, 1.1f) == false || - itk::Math::AlmostEquals(1, 1.0) == false || itk::Math::AlmostEquals(2.0, 1.0) || itk::Math::AlmostEquals(1, 2)) - { - std::cout << __FILE__ << ' ' << __LINE__ << ' ' << f << " == " << d << std::endl; - testPassStatus = EXIT_FAILURE; - } - - // Test ExactlyEquals() it should detect normal inequalities - if (itk::Math::ExactlyEquals(f, d) || itk::Math::ExactlyEquals(d, f)) - { - std::cout << __FILE__ << ' ' << __LINE__ << ' ' << f << " == " << d << std::endl; - testPassStatus = EXIT_FAILURE; - } - - // Test comparison values of different types - if (itk::Math::NotExactlyEquals(1.0f, 1.0) || itk::Math::NotExactlyEquals(1.0, 1.0f)) - { - std::cout << __FILE__ << ' ' << __LINE__ << ' ' << f << " == " << d << std::endl; - testPassStatus = EXIT_FAILURE; - } - - // Test comparison of very close values - FloatRepresentationD oneExact; - FloatRepresentationD oneAlmost; - - oneExact.asFloat = 1.0; - oneAlmost.asFloat = 1.0; - oneAlmost.asInt += 1; - - // Very close values should be AlmostEqual - if (itk::Math::NotAlmostEquals(oneExact.asFloat, oneAlmost.asFloat)) - { - std::cout << __FILE__ << ' ' << __LINE__ << ' ' << oneExact.asFloat << " == " << oneAlmost.asFloat << std::endl; - std::cout << "AlmostEquals Test Failure\n" << std::endl; - testPassStatus = EXIT_FAILURE; - } - - // Even very close values are not ExactlyEqual - if (itk::Math::ExactlyEquals(oneExact.asFloat, oneAlmost.asFloat)) - { - std::cout << __FILE__ << ' ' << __LINE__ << ' ' << oneExact.asFloat << " == " << oneAlmost.asFloat << std::endl; - std::cout << "ExactlyEquals Test Failure\n" << std::endl; - testPassStatus = EXIT_FAILURE; - } - - // Test AlmostEquals complex comparisons - constexpr std::complex z1Double(1.1, 2.1); - constexpr std::complex z1Float(1.1f, 2.1f); - - // Test AlmostEquals with complex numbers of the same value and different types - std::cout << "Testing COMPLEX vs COMPLEX, DOUBLE vs FLOAT, SAME values " << std::endl; - if (itk::Math::AlmostEquals(z1Double, z1Float) == false) - { - std::cout << "Test FAILED!!\n" << std::endl; - std::cout << __FILE__ << ' ' << __LINE__ << ' ' << f << " == " << d << std::endl; - testPassStatus = EXIT_FAILURE; - } - else - { - std::cout << "Test passed\n" << std::endl; - } - -#if !defined(ITK_LEGACY_REMOVE) - constexpr std::complex z2Double(1.0, 3.0); - constexpr std::complex z2Int(1, 3); - - std::cout << "Testing COMPLEX vs COMPLEX, DOUBLE vs INT, SAME values " << std::endl; - if (itk::Math::AlmostEquals(z2Double, z2Int) == false) - { - std::cout << "Test FAILED!!\n" << std::endl; - std::cout << __FILE__ << ' ' << __LINE__ << ' ' << f << " == " << d << std::endl; - testPassStatus = EXIT_FAILURE; - } - else - { - std::cout << "Test passed\n" << std::endl; - } -#endif // !defined(ITK_LEGACY_REMOVE) - - // Test Comparisons with complex values that are very close - FloatRepresentationD z1AlmostRealPart; - z1AlmostRealPart.asFloat = z1Double.real(); - z1AlmostRealPart.asInt += 1; - const std::complex z1DoubleAlmost(z1AlmostRealPart.asFloat, z1Double.imag()); - - std::cout << "Testing COMPLEX vs COMPLEX, DOUBLE vs DOUBLE, VERYCLOSE values " << std::endl; - if (itk::Math::NotAlmostEquals(z1Double, z1DoubleAlmost)) - { - std::cout << "Test FAILED!!\n" << std::endl; - std::cout << __FILE__ << ' ' << __LINE__ << ' ' << f << " == " << d << std::endl; - testPassStatus = EXIT_FAILURE; - } - else - { - std::cout << "Test passed\n" << std::endl; - } - - // Test comparison between complex and real number with the same value - constexpr std::complex z3Double(0.123, 0); - constexpr float r3Float{ 0.123 }; - constexpr double r3Double{ 0.123 }; - - std::cout << "Testing COMPLEX vs REAL, DOUBLE vs DOUBLE, SAME values " << std::endl; - if (itk::Math::NotAlmostEquals(z3Double, r3Double)) - { - std::cout << "Test FAILED!!\n" << std::endl; - std::cout << __FILE__ << ' ' << __LINE__ << ' ' << f << " == " << d << std::endl; - testPassStatus = EXIT_FAILURE; - } - else - { - std::cout << "Test passed\n" << std::endl; - } - - std::cout << "Testing COMPLEX vs REAL, DOUBLE vs FLOAT, SAME values " << std::endl; - if (itk::Math::NotAlmostEquals(z3Double, r3Float)) - { - std::cout << "Test FAILED!!\n" << std::endl; - std::cout << __FILE__ << ' ' << __LINE__ << ' ' << f << " == " << d << std::endl; - testPassStatus = EXIT_FAILURE; - } - else - { - std::cout << "Test passed\n" << std::endl; - } - - // Test comparison between complex and real numbers with very close values - constexpr std::complex z4Float(0.123, 0); - FloatRepresentationF r4FloatAlmost; - r4FloatAlmost.asFloat = z4Float.real(); - r4FloatAlmost.asInt += 1; - - std::cout << "Testing COMPLEX vs REAL, FLOAT vs FLOAT, VERYCLOSE values " << std::endl; - if (itk::Math::NotAlmostEquals(z4Float, r4FloatAlmost.asFloat)) - { - std::cout << "Test FAILED!!\n" << std::endl; - std::cout << __FILE__ << ' ' << __LINE__ << ' ' << f << " == " << d << std::endl; - testPassStatus = EXIT_FAILURE; - } - else - { - std::cout << "Test passed\n" << std::endl; - } - - std::cout << "Testing COMPLEX vs REAL, DOUBLE vs FLOAT, VERYCLOSE values " << std::endl; - if (itk::Math::NotAlmostEquals(z3Double, r4FloatAlmost.asFloat)) - { - std::cout << "Test FAILED!!\n" << std::endl; - std::cout << __FILE__ << ' ' << __LINE__ << ' ' << f << " == " << d << std::endl; - testPassStatus = EXIT_FAILURE; - } - else - { - std::cout << "Test passed\n" << std::endl; - } - } - - // Test the itk::Math::IsPrime methods - std::cout << "Testing itk::Math::IsPrime" << std::endl; - if (ExerciseIsPrime()) - { - std::cout << "Test FAILED!!" << std::endl; - testPassStatus = EXIT_FAILURE; - } - else - { - std::cout << "Test passed" << std::endl; - } - - if (ExerciseIsPrime()) - { - std::cout << "Test FAILED!!" << std::endl; - testPassStatus = EXIT_FAILURE; - } - else - { - std::cout << "Test passed" << std::endl; - } - - if (ExerciseIsPrime()) - { - std::cout << "Test FAILED!!" << std::endl; - testPassStatus = EXIT_FAILURE; - } - else - { - std::cout << "Test passed" << std::endl; - } - - if (ExerciseIsPrime()) - { - std::cout << "Test FAILED!!" << std::endl; - testPassStatus = EXIT_FAILURE; - } - else - { - std::cout << "Test passed" << std::endl; - } - - // Test the itk::Math::GreatestPrimeFactor methods - std::cout << "Testing itk::Math::GreatestPrimeFactor" << std::endl; - if (ExerciseGreatestPrimeFactor()) - { - std::cout << "Test FAILED!!" << std::endl; - testPassStatus = EXIT_FAILURE; - } - else - { - std::cout << "Test passed" << std::endl; - } - - if (ExerciseGreatestPrimeFactor()) - { - std::cout << "Test FAILED!!" << std::endl; - testPassStatus = EXIT_FAILURE; - } - else - { - std::cout << "Test passed" << std::endl; - } - - if (ExerciseGreatestPrimeFactor()) - { - std::cout << "Test FAILED!!" << std::endl; - testPassStatus = EXIT_FAILURE; - } - else - { - std::cout << "Test passed" << std::endl; - } - - if (ExerciseGreatestPrimeFactor()) - { - std::cout << "Test FAILED!!" << std::endl; - testPassStatus = EXIT_FAILURE; - } - else - { - std::cout << "Test passed" << std::endl; - } - - // Test the itk::Math::abs methods - std::cout << "Testing itk::Math::abs integral overloads" << std::endl; - // Specify template arguments to avoid choosing non-constexpr std::abs overloads - static_assert(itk::Math::safe_abs(false) == false); - static_assert(itk::Math::safe_abs(true) == true); - static_assert(itk::Math::safe_abs((unsigned char)5) == 5); - static_assert(itk::Math::safe_abs((unsigned short)5) == 5); - static_assert(itk::Math::safe_abs((unsigned int)5) == 5); - static_assert(itk::Math::safe_abs((unsigned long)5) == 5); - static_assert(itk::Math::safe_abs((unsigned long long)5) == 5); - - static_assert(itk::Math::safe_abs((signed char)-5) == 5); - static_assert(itk::Math::safe_abs((signed char)-128) == 128); - - static_assert(itk::Math::safe_abs((short)-5) == 5); - - static_assert(itk::Math::safe_abs(-5) == 5u); - static_assert(itk::Math::safe_abs(-5L) == 5ul); - static_assert(itk::Math::safe_abs(-5LL) == 5ull); - - static_assert(itk::Math::safe_abs(-5.0) == 5.0); - static_assert(itk::Math::safe_abs(-5.0f) == 5.0f); - - // complex types are never constexpr for abs or safe_abs - const auto cf = std::complex(-3, -4); - ITK_TEST_EXPECT_EQUAL(itk::Math::safe_abs(cf), 5); - const auto cd = std::complex(-3, -4); - ITK_TEST_EXPECT_EQUAL(itk::Math::safe_abs(cd), 5); - const auto cld = std::complex(-3, -4); - ITK_TEST_EXPECT_EQUAL(itk::Math::safe_abs(cld), 5); - - // test backward compatible non-constexpr abs function - ITK_TEST_EXPECT_EQUAL(itk::Math::abs(false), false); - ITK_TEST_EXPECT_EQUAL(itk::Math::abs(true), true); - ITK_TEST_EXPECT_EQUAL(itk::Math::abs((unsigned char)5), 5); - ITK_TEST_EXPECT_EQUAL(itk::Math::abs((signed char)-5), 5); - ITK_TEST_EXPECT_EQUAL(itk::Math::abs((signed char)-128), 128); - ITK_TEST_EXPECT_EQUAL(itk::Math::abs((short)-5), 5); - // Specify template arguments to avoid choosing non-constexpr std::abs overloads - ITK_TEST_EXPECT_EQUAL(itk::Math::abs(-5), 5u); - ITK_TEST_EXPECT_EQUAL(itk::Math::abs(-5L), 5ul); - ITK_TEST_EXPECT_EQUAL(itk::Math::abs(-5LL), 5ull); - - ITK_TEST_EXPECT_EQUAL(itk::Math::abs(-5.0), 5.0); - ITK_TEST_EXPECT_EQUAL(itk::Math::abs(-5.0f), 5.0f); - - - if (itk::Math::abs((signed char)-128) != 128) - { - std::cout << "itk::Math::abs((signed char)-128) FAILED!" << std::endl; - testPassStatus = EXIT_FAILURE; - } - - if (itk::Math::abs(-5) != 5) - { - std::cout << "itk::Math::abs(-5) FAILED!" << std::endl; - testPassStatus = EXIT_FAILURE; - } - - - return testPassStatus; -}