Skip to content

Commit 038018d

Browse files
authored
Merge pull request #5798 from InsightSoftwareConsortium/add-constexpr-for-math-operations
add constexpr for math operations
2 parents 18886af + 532b323 commit 038018d

File tree

7 files changed

+492
-1142
lines changed

7 files changed

+492
-1142
lines changed

Modules/Core/Common/include/itkMath.h

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ static constexpr float float_sqrteps = vnl_math::float_sqrteps;
104104
* bit, the 64 bit or the vanilla version */
105105
#define itkTemplateFloatingToIntegerMacro(name) \
106106
template <typename TReturn, typename TInput> \
107-
inline TReturn name(TInput x) \
107+
inline constexpr auto name(TInput x) \
108108
{ \
109109
if constexpr (sizeof(TReturn) <= 4) \
110110
{ \
@@ -173,7 +173,7 @@ itkTemplateFloatingToIntegerMacro(RoundHalfIntegerUp)
173173
* \sa RoundHalfIntegerUp<TReturn, TInput>()
174174
*/
175175
template <typename TReturn, typename TInput>
176-
inline TReturn
176+
inline constexpr auto
177177
Round(TInput x)
178178
{
179179
return RoundHalfIntegerUp<TReturn, TInput>(x);
@@ -208,7 +208,7 @@ itkTemplateFloatingToIntegerMacro(Ceil)
208208
#undef itkTemplateFloatingToIntegerMacro
209209

210210
template <typename TReturn, typename TInput>
211-
inline TReturn
211+
inline auto
212212
CastWithRangeCheck(TInput x)
213213
{
214214
itkConceptMacro(OnlyDefinedForIntegerTypes1, (itk::Concept::IsInteger<TReturn>));
@@ -247,7 +247,7 @@ CastWithRangeCheck(TInput x)
247247
* \sa FloatAddULP
248248
*/
249249
template <typename T>
250-
inline typename Detail::FloatIEEE<T>::IntType
250+
inline constexpr typename Detail::FloatIEEE<T>::IntType
251251
FloatDifferenceULP(T x1, T x2)
252252
{
253253
const Detail::FloatIEEE<T> x1f(x1);
@@ -263,7 +263,7 @@ FloatDifferenceULP(T x1, T x2)
263263
* \sa FloatDifferenceULP
264264
*/
265265
template <typename T>
266-
inline T
266+
inline constexpr T
267267
FloatAddULP(T x, typename Detail::FloatIEEE<T>::IntType ulps)
268268
{
269269
const Detail::FloatIEEE<T> representInput(x);
@@ -714,7 +714,7 @@ NotAlmostEquals(T1 x1, T2 x2)
714714

715715
// The ExactlyEquals function
716716
template <typename TInput1, typename TInput2>
717-
inline bool
717+
inline constexpr bool
718718
ExactlyEquals(const TInput1 & x1, const TInput2 & x2)
719719
{
720720
ITK_GCC_PRAGMA_PUSH
@@ -725,7 +725,7 @@ ExactlyEquals(const TInput1 & x1, const TInput2 & x2)
725725

726726
// The NotExactlyEquals function
727727
template <typename TInput1, typename TInput2>
728-
inline bool
728+
inline constexpr bool
729729
NotExactlyEquals(const TInput1 & x1, const TInput2 & x2)
730730
{
731731
return !ExactlyEquals(x1, x2);
@@ -737,33 +737,64 @@ NotExactlyEquals(const TInput1 & x1, const TInput2 & x2)
737737
* \note Negative numbers cannot be prime.
738738
*/
739739
/** @ITKStartGrouping */
740-
ITKCommon_EXPORT bool
741-
IsPrime(unsigned short n);
742-
ITKCommon_EXPORT bool
743-
IsPrime(unsigned int n);
744-
ITKCommon_EXPORT bool
745-
IsPrime(unsigned long n);
746-
ITKCommon_EXPORT bool
747-
IsPrime(unsigned long long n);
740+
template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
741+
constexpr bool
742+
IsPrime(T n)
743+
{
744+
// An Introduction to the Theory of Numbers — G.H. Hardy & E.M. Wright, 6th ed., Oxford University Press.
745+
// See Chapter 1 (Elementary Results on Primes). The observation that primes > 3 lie in residue classes
746+
// +/1 mod 6 follows directly from eliminating multiples of 2 and 3.
747+
if (n <= 1)
748+
{
749+
return false;
750+
}
751+
if (n == 2 || n == 3)
752+
{
753+
return true;
754+
}
755+
if (n % 2 == 0 || n % 3 == 0)
756+
{
757+
return false;
758+
}
759+
// 6k +/- 1, and avoid overflow via i <= n / i
760+
for (T x = 5; x <= n / x; x += 6)
761+
{
762+
if (n % x == 0 || n % (x + 2) == 0)
763+
{
764+
return false;
765+
}
766+
}
767+
return true;
768+
}
748769
/** @ITKEndGrouping */
749770

750771
/** Return the greatest factor of the decomposition in prime numbers. */
751772
/** @ITKStartGrouping */
752-
ITKCommon_EXPORT unsigned short
753-
GreatestPrimeFactor(unsigned short n);
754-
ITKCommon_EXPORT unsigned int
755-
GreatestPrimeFactor(unsigned int n);
756-
ITKCommon_EXPORT unsigned long
757-
GreatestPrimeFactor(unsigned long n);
758-
ITKCommon_EXPORT unsigned long long
759-
GreatestPrimeFactor(unsigned long long n);
773+
template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
774+
constexpr T
775+
GreatestPrimeFactor(T n)
776+
{
777+
T v = 2;
778+
while (v <= n)
779+
{
780+
if (n % v == 0 && IsPrime(v))
781+
{
782+
n /= v;
783+
}
784+
else
785+
{
786+
v += 1;
787+
}
788+
}
789+
return v;
790+
}
760791
/** @ITKEndGrouping */
761792

762793
/** Returns `a * b`. Numeric overflow triggers a compilation error in
763794
* "constexpr context" and a debug assert failure at run-time.
764795
*/
765796
template <typename TReturnType = uintmax_t>
766-
constexpr TReturnType
797+
constexpr auto
767798
UnsignedProduct(const uintmax_t a, const uintmax_t b) noexcept
768799
{
769800
static_assert(std::is_unsigned_v<TReturnType>, "UnsignedProduct only supports unsigned return types");
@@ -785,8 +816,8 @@ UnsignedProduct(const uintmax_t a, const uintmax_t b) noexcept
785816
* no agreed-upon value: https://en.wikipedia.org/wiki/Zero_to_the_power_of_zero
786817
*/
787818
template <typename TReturnType = uintmax_t>
788-
constexpr TReturnType
789-
UnsignedPower(const uintmax_t base, const uintmax_t exponent) noexcept
819+
constexpr auto
820+
UnsignedPower(const uintmax_t base, const uintmax_t exponent) noexcept -> TReturnType
790821
{
791822
static_assert(std::is_unsigned_v<TReturnType>, "UnsignedPower only supports unsigned return types");
792823

Modules/Core/Common/include/itkMathDetail.h

Lines changed: 43 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ ITK_GCC_PRAGMA_PUSH
8989
ITK_GCC_SUPPRESS_Wfloat_equal
9090

9191
template <typename TReturn, typename TInput>
92-
inline TReturn
92+
constexpr TReturn
9393
RoundHalfIntegerToEven_base(TInput x)
9494
{
9595
if (NumericTraits<TInput>::IsNonnegative(x))
@@ -106,7 +106,7 @@ RoundHalfIntegerToEven_base(TInput x)
106106
}
107107

108108
template <typename TReturn, typename TInput>
109-
inline TReturn
109+
constexpr TReturn
110110
RoundHalfIntegerUp_base(TInput x)
111111
{
112112
x += static_cast<TInput>(0.5);
@@ -116,7 +116,7 @@ RoundHalfIntegerUp_base(TInput x)
116116
}
117117

118118
template <typename TReturn, typename TInput>
119-
inline TReturn
119+
constexpr TReturn
120120
Floor_base(TInput x)
121121
{
122122
const auto r = static_cast<TReturn>(x);
@@ -126,7 +126,7 @@ Floor_base(TInput x)
126126
}
127127

128128
template <typename TReturn, typename TInput>
129-
inline TReturn
129+
constexpr TReturn
130130
Ceil_base(TInput x)
131131
{
132132
const auto r = static_cast<TReturn>(x);
@@ -217,15 +217,11 @@ RoundHalfIntegerToEven_32(float x)
217217

218218
#else // Base implementation
219219

220-
inline int32_t
221-
RoundHalfIntegerToEven_32(double x)
220+
template <typename TInput>
221+
constexpr int32_t
222+
RoundHalfIntegerToEven_32(TInput x)
222223
{
223-
return RoundHalfIntegerToEven_base<int32_t, double>(x);
224-
}
225-
inline int32_t
226-
RoundHalfIntegerToEven_32(float x)
227-
{
228-
return RoundHalfIntegerToEven_base<int32_t, float>(x);
224+
return RoundHalfIntegerToEven_base<int32_t, TInput>(x);
229225
}
230226

231227
#endif
@@ -267,37 +263,25 @@ Ceil_32(float x)
267263

268264
#else // Base implementation
269265

270-
inline int32_t
271-
RoundHalfIntegerUp_32(double x)
272-
{
273-
return RoundHalfIntegerUp_base<int32_t, double>(x);
274-
}
275-
inline int32_t
276-
RoundHalfIntegerUp_32(float x)
266+
template <typename TInput>
267+
constexpr int32_t
268+
RoundHalfIntegerUp_32(TInput x)
277269
{
278-
return RoundHalfIntegerUp_base<int32_t, float>(x);
270+
return RoundHalfIntegerUp_base<int32_t, TInput>(x);
279271
}
280272

281-
inline int32_t
282-
Floor_32(double x)
283-
{
284-
return Floor_base<int32_t, double>(x);
285-
}
286-
inline int32_t
287-
Floor_32(float x)
273+
template <typename TInput>
274+
constexpr int32_t
275+
Floor_32(TInput x)
288276
{
289-
return Floor_base<int32_t, float>(x);
277+
return Floor_base<int32_t, TInput>(x);
290278
}
291279

292-
inline int32_t
293-
Ceil_32(double x)
294-
{
295-
return Ceil_base<int32_t, double>(x);
296-
}
297-
inline int32_t
298-
Ceil_32(float x)
280+
template <typename TInput>
281+
constexpr int32_t
282+
Ceil_32(TInput x)
299283
{
300-
return Ceil_base<int32_t, float>(x);
284+
return Ceil_base<int32_t, TInput>(x);
301285
}
302286

303287
#endif // USE_SSE2_32IMPL || GCC_USE_ASM_32IMPL || VC_USE_ASM_32IMPL
@@ -383,15 +367,11 @@ RoundHalfIntegerToEven_64(float x)
383367

384368
#else // Base implementation
385369

386-
inline int64_t
387-
RoundHalfIntegerToEven_64(double x)
388-
{
389-
return RoundHalfIntegerToEven_base<int64_t, double>(x);
390-
}
391-
inline int64_t
392-
RoundHalfIntegerToEven_64(float x)
370+
template <typename TInput>
371+
constexpr int64_t
372+
RoundHalfIntegerToEven_64(TInput x)
393373
{
394-
return RoundHalfIntegerToEven_base<int64_t, float>(x);
374+
return RoundHalfIntegerToEven_base<int64_t, TInput>(x);
395375
}
396376

397377
#endif
@@ -433,37 +413,25 @@ Ceil_64(float x)
433413

434414
#else // Base implementation
435415

436-
inline int64_t
437-
RoundHalfIntegerUp_64(double x)
438-
{
439-
return RoundHalfIntegerUp_base<int64_t, double>(x);
440-
}
441-
inline int64_t
442-
RoundHalfIntegerUp_64(float x)
416+
template <typename TInput>
417+
constexpr int64_t
418+
RoundHalfIntegerUp_64(TInput x)
443419
{
444-
return RoundHalfIntegerUp_base<int64_t, float>(x);
420+
return RoundHalfIntegerUp_base<int64_t, TInput>(x);
445421
}
446422

447-
inline int64_t
448-
Floor_64(double x)
449-
{
450-
return Floor_base<int64_t, double>(x);
451-
}
452-
inline int64_t
453-
Floor_64(float x)
423+
template <typename TInput>
424+
constexpr int64_t
425+
Floor_64(TInput x)
454426
{
455-
return Floor_base<int64_t, float>(x);
427+
return Floor_base<int64_t, TInput>(x);
456428
}
457429

458-
inline int64_t
459-
Ceil_64(double x)
460-
{
461-
return Ceil_base<int64_t, double>(x);
462-
}
463-
inline int64_t
464-
Ceil_64(float x)
430+
template <typename TInput>
431+
constexpr int64_t
432+
Ceil_64(TInput x)
465433
{
466-
return Ceil_base<int64_t, float>(x);
434+
return Ceil_base<int64_t, TInput>(x);
467435
}
468436

469437
#endif // USE_SSE2_64IMPL || GCC_USE_ASM_64IMPL || VC_USE_ASM_64IMPL
@@ -496,18 +464,21 @@ union FloatIEEE
496464
IntType asInt;
497465
UIntType asUInt;
498466

499-
FloatIEEE(FloatType f)
467+
constexpr FloatIEEE(FloatType f)
500468
: asFloat(f)
501469
{}
502-
FloatIEEE(IntType i)
470+
constexpr FloatIEEE(IntType i)
503471
: asInt(i)
504472
{}
505-
[[nodiscard]] bool
473+
constexpr FloatIEEE(UIntType ui)
474+
: asUInt(ui)
475+
{}
476+
[[nodiscard]] constexpr bool
506477
Sign() const
507478
{
508479
return (asUInt >> (sizeof(asUInt) * 8 - 1)) != 0;
509480
}
510-
[[nodiscard]] IntType
481+
[[nodiscard]] constexpr IntType
511482
AsULP() const
512483
{
513484
return this->Sign() ? IntType(~(~UIntType(0) >> 1) - asUInt) : asInt;

Modules/Core/Common/src/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ set(
147147
itkArrayOutputSpecialization.cxx
148148
itkNumberToString.cxx
149149
itkRandomVariateGeneratorBase.cxx
150-
itkMath.cxx
151150
itkProgressTransformer.cxx
152151
itkSymmetricEigenAnalysis.cxx
153152
itkExtractImageFilter.cxx

0 commit comments

Comments
 (0)