Skip to content

Commit 71e5259

Browse files
committed
ENH: Define itk::Math constants from literals and C++20 std::numbers
Replace the vnl_math:: aliases with self-contained definitions: the correctly-rounded double literals (OEIS-referenced) are the fallback, and when C++20 <numbers> is available the std::numbers constants, or constexpr arithmetic on them, are used instead. This decouples itk::Math from vnl_math, whose constants are slated for deprecation and eventual removal in upstream vxl. itk::Math no longer depends on those aliases remaining available. sqrt2pi has no std::numbers counterpart and std::sqrt is not constexpr before C++26, so it stays a literal in both paths.
1 parent 149b32f commit 71e5259

3 files changed

Lines changed: 45 additions & 32 deletions

File tree

Modules/Core/Common/include/itkMath.h

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@
3333
#include <cmath>
3434
#include <limits>
3535
#include <type_traits>
36+
// _MSVC_LANG tracks /std: even when __cplusplus stays 199711L (no /Zc:__cplusplus),
37+
// matching the STL condition under which <limits> defines __cpp_lib_math_constants.
38+
#if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
39+
# include <numbers>
40+
#endif
3641
#include "itkMathDetail.h"
3742
#include "itkConceptChecking.h"
3843
#include <vnl/vnl_math.h>
@@ -46,59 +51,67 @@
4651

4752
namespace itk::Math
4853
{
49-
// These constants originate from VXL's vnl_math.h. They are exposed as
50-
// inline constexpr namespace-scope constants so they are usable in
51-
// constant expressions with a single shared definition across translation
52-
// units.
53-
54+
// These mathematical constants originate from VXL's vnl_math.h. The literal
55+
// fallback values are the correctly-rounded double-precision constants (OEIS
56+
// references in vnl_math.h). When C++20 <numbers> is available, the standard
57+
// constants (or constexpr arithmetic on them) are used instead.
58+
#if defined(__cpp_lib_math_constants)
59+
# define itkMATH_STD_OR_LITERAL(std_value, literal_value) (std_value)
60+
#else
61+
# define itkMATH_STD_OR_LITERAL(std_value, literal_value) (literal_value)
62+
#endif
5463

5564
/** \brief \f[e\f] The base of the natural logarithm or Euler's number */
56-
inline constexpr double e = vnl_math::e;
65+
inline constexpr double e = itkMATH_STD_OR_LITERAL(std::numbers::e, 2.71828182845904523536);
5766
/** \brief \f[ \log_2 e \f] */
58-
inline constexpr double log2e = vnl_math::log2e;
67+
inline constexpr double log2e = itkMATH_STD_OR_LITERAL(std::numbers::log2e, 1.44269504088896340736);
5968
/** \brief \f[ \log_{10} e \f] */
60-
inline constexpr double log10e = vnl_math::log10e;
69+
inline constexpr double log10e = itkMATH_STD_OR_LITERAL(std::numbers::log10e, 0.43429448190325182765);
6170
/** \brief \f[ \log_e 2 \f] */
62-
inline constexpr double ln2 = vnl_math::ln2;
71+
inline constexpr double ln2 = itkMATH_STD_OR_LITERAL(std::numbers::ln2, 0.69314718055994530942);
6372
/** \brief \f[ \log_e 10 \f] */
64-
inline constexpr double ln10 = vnl_math::ln10;
73+
inline constexpr double ln10 = itkMATH_STD_OR_LITERAL(std::numbers::ln10, 2.30258509299404568402);
6574
/** \brief \f[ \pi \f] */
66-
inline constexpr double pi = vnl_math::pi;
75+
inline constexpr double pi = itkMATH_STD_OR_LITERAL(std::numbers::pi, 3.14159265358979323846);
6776
/** \brief \f[ 2\pi \f] */
68-
inline constexpr double twopi = vnl_math::twopi;
77+
inline constexpr double twopi = itkMATH_STD_OR_LITERAL(2 * std::numbers::pi, 6.28318530717958647693);
6978
/** \brief \f[ \frac{\pi}{2} \f] */
70-
inline constexpr double pi_over_2 = vnl_math::pi_over_2;
79+
inline constexpr double pi_over_2 = itkMATH_STD_OR_LITERAL(std::numbers::pi / 2, 1.57079632679489661923);
7180
/** \brief \f[ \frac{\pi}{4} \f] */
72-
inline constexpr double pi_over_4 = vnl_math::pi_over_4;
81+
inline constexpr double pi_over_4 = itkMATH_STD_OR_LITERAL(std::numbers::pi / 4, 0.78539816339744830962);
7382
/** \brief \f[ \frac{\pi}{180} \f] */
74-
inline constexpr double pi_over_180 = vnl_math::pi_over_180;
83+
inline constexpr double pi_over_180 = itkMATH_STD_OR_LITERAL(std::numbers::pi / 180, 0.01745329251994329577);
7584
/** \brief \f[ \frac{1}{\pi} \f] */
76-
inline constexpr double one_over_pi = vnl_math::one_over_pi;
85+
inline constexpr double one_over_pi = itkMATH_STD_OR_LITERAL(std::numbers::inv_pi, 0.31830988618379067154);
7786
/** \brief \f[ \frac{2}{\pi} \f] */
78-
inline constexpr double two_over_pi = vnl_math::two_over_pi;
87+
inline constexpr double two_over_pi = itkMATH_STD_OR_LITERAL(2 * std::numbers::inv_pi, 0.63661977236758134308);
7988
/** \brief \f[ \frac{180}{\pi} \f] */
80-
inline constexpr double deg_per_rad = vnl_math::deg_per_rad;
89+
inline constexpr double deg_per_rad = itkMATH_STD_OR_LITERAL(180 * std::numbers::inv_pi, 57.2957795130823208768);
8190
/** \brief \f[ \sqrt{2\pi} \f] */
82-
inline constexpr double sqrt2pi = vnl_math::sqrt2pi;
91+
inline constexpr double sqrt2pi =
92+
2.50662827463100050242; // no std::numbers constant; std::sqrt not constexpr until C++26
8393
/** \brief \f[ \frac{2}{\sqrt{\pi}} \f] */
84-
inline constexpr double two_over_sqrtpi = vnl_math::two_over_sqrtpi;
94+
inline constexpr double two_over_sqrtpi = itkMATH_STD_OR_LITERAL(2 * std::numbers::inv_sqrtpi, 1.12837916709551257390);
8595
/** \brief \f[ \frac{1}{\sqrt{2\pi}} \f] */
86-
inline constexpr double one_over_sqrt2pi = vnl_math::one_over_sqrt2pi;
96+
inline constexpr double one_over_sqrt2pi =
97+
itkMATH_STD_OR_LITERAL(std::numbers::inv_sqrtpi / std::numbers::sqrt2, 0.39894228040143267794);
8798
/** \brief \f[ \sqrt{2} \f] */
88-
inline constexpr double sqrt2 = vnl_math::sqrt2;
99+
inline constexpr double sqrt2 = itkMATH_STD_OR_LITERAL(std::numbers::sqrt2, 1.41421356237309504880);
89100
/** \brief \f[ \sqrt{ \frac{1}{2}} \f] */
90-
inline constexpr double sqrt1_2 = vnl_math::sqrt1_2;
101+
inline constexpr double sqrt1_2 = itkMATH_STD_OR_LITERAL(std::numbers::sqrt2 / 2, 0.70710678118654752440);
91102
/** \brief \f[ \sqrt{ \frac{1}{3}} \f] */
92-
inline constexpr double sqrt1_3 = vnl_math::sqrt1_3;
103+
inline constexpr double sqrt1_3 = itkMATH_STD_OR_LITERAL(std::numbers::inv_sqrt3, 0.57735026918962576451);
93104
/** \brief euler constant */
94-
inline constexpr double euler = vnl_math::euler;
105+
inline constexpr double euler = itkMATH_STD_OR_LITERAL(std::numbers::egamma, 0.57721566490153286061);
106+
107+
#undef itkMATH_STD_OR_LITERAL
95108

96109
//: IEEE double machine precision
97-
inline constexpr double eps = vnl_math::eps;
98-
inline constexpr double sqrteps = vnl_math::sqrteps;
110+
inline constexpr double eps = std::numeric_limits<double>::epsilon();
111+
inline constexpr double sqrteps = 1.490116119384766e-08;
99112
//: IEEE single machine precision
100-
inline constexpr float float_eps = vnl_math::float_eps;
101-
inline constexpr float float_sqrteps = vnl_math::float_sqrteps;
113+
inline constexpr float float_eps = std::numeric_limits<float>::epsilon();
114+
inline constexpr float float_sqrteps = 3.4526698300e-4F;
102115

103116
/** A useful macro to generate a template floating point to integer
104117
* conversion templated on the return type and using either the 32

Modules/Filtering/PhaseSymmetry/include/itkSinusoidSpatialFunction.hxx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
#define itkSinusoidSpatialFunction_hxx
2020

2121
#include <cmath>
22-
#include "vnl/vnl_math.h"
22+
#include "itkMath.h"
2323

2424
namespace itk
2525
{
@@ -45,7 +45,7 @@ SinusoidSpatialFunction<TOutput, VImageDimension, TInput>::Evaluate(const TInput
4545
{
4646
frequencyTerm += this->m_Frequency[ii] * position[ii];
4747
}
48-
frequencyTerm *= 2.0 * vnl_math::pi;
48+
frequencyTerm *= 2.0 * itk::Math::pi;
4949
frequencyTerm += this->m_PhaseOffset;
5050
const double value = std::cos(frequencyTerm);
5151
return static_cast<TOutput>(value);

Modules/IO/NIFTI/test/itkNiftiReadWriteDirectionTest.cxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ itkNiftiReadWriteDirectionTest(int argc, char * argv[])
259259
const double trace = rRelative[0][0] + rRelative[1][1] + rRelative[2][2];
260260

261261
// Calculate the angle of rotation between the two matrices
262-
const double angle = std::acos((trace - 1.0) / 2.0) * 180.0 / vnl_math::pi;
262+
const double angle = std::acos((trace - 1.0) / 2.0) * 180.0 / itk::Math::pi;
263263

264264
// The angle between the two matrices will depend on the amount of shear in the sform. Some test images
265265
// have relatively large shear to make sure they trigger the sform correction. In practice, permissive mode

0 commit comments

Comments
 (0)