Skip to content

Commit fcc80ce

Browse files
committed
ENH: Harden itk::Math natives beyond vnl_math parity
Improvements over the vnl_math variants these functions replace: - squared_magnitude(int/long/long long): multiply in the unsigned type; vnl's x * x is signed-overflow UB for |x| > sqrt(max). - remainder_floored (signed integral): single-modulo conditional add; vnl's ((x % y) + y) % y overflows the intermediate for |y| > max/2. - angle_0_to_2pi: drop an unreachable tail return inherited from vnl.
1 parent ea24f1d commit fcc80ce

1 file changed

Lines changed: 12 additions & 10 deletions

File tree

Modules/Core/Common/include/itkMath.h

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -922,7 +922,9 @@ squared_magnitude(unsigned char x)
922922
constexpr unsigned int
923923
squared_magnitude(int x)
924924
{
925-
return static_cast<unsigned int>(x * x);
925+
// Multiply in unsigned: avoids the signed-overflow UB of vnl_math's x * x.
926+
const auto ux = static_cast<unsigned int>(x);
927+
return ux * ux;
926928
}
927929
constexpr unsigned int
928930
squared_magnitude(unsigned int x)
@@ -932,7 +934,8 @@ squared_magnitude(unsigned int x)
932934
constexpr unsigned long
933935
squared_magnitude(long x)
934936
{
935-
return static_cast<unsigned long>(x * x);
937+
const auto ux = static_cast<unsigned long>(x);
938+
return ux * ux;
936939
}
937940
constexpr unsigned long
938941
squared_magnitude(unsigned long x)
@@ -942,7 +945,8 @@ squared_magnitude(unsigned long x)
942945
constexpr unsigned long long
943946
squared_magnitude(long long x)
944947
{
945-
return static_cast<unsigned long long>(x * x);
948+
const auto ux = static_cast<unsigned long long>(x);
949+
return ux * ux;
946950
}
947951
constexpr unsigned long long
948952
squared_magnitude(unsigned long long x)
@@ -993,7 +997,9 @@ template <typename T, std::enable_if_t<std::is_integral_v<T> && std::is_signed_v
993997
constexpr T
994998
remainder_floored(T x, T y)
995999
{
996-
return ((x % y) + y) % y;
1000+
// Conditional add: vnl_math's ((x % y) + y) % y overflows for |y| > max/2.
1001+
const T r = x % y;
1002+
return (r != 0 && ((r < 0) != (y < 0))) ? r + y : r;
9971003
}
9981004
template <typename T, std::enable_if_t<std::is_integral_v<T> && std::is_unsigned_v<T>, int> = 0>
9991005
constexpr T
@@ -1086,12 +1092,8 @@ angle_0_to_2pi(double angle)
10861092
if (angle >= 0)
10871093
return angle;
10881094
const double a = angle + twopi;
1089-
if (a > 0 && a < twopi)
1090-
return a;
1091-
// Guard the boundary: tiny negative inputs can produce exactly twopi above.
1092-
if (angle < 0)
1093-
return 6.28318530717958575;
1094-
return angle;
1095+
// Guard the boundary: tiny negative inputs round a up to exactly twopi; clamp 1 ULP below.
1096+
return (a < twopi) ? a : 6.28318530717958575;
10951097
}
10961098

10971099
/** \brief Normalize an angle (radians) into (-pi, pi]. */

0 commit comments

Comments
 (0)