Skip to content

Commit 600627d

Browse files
authored
Merge pull request #1417 from boostorg/mac_roots
Fix UB in sorting results with the cubic root finder
2 parents fe74e79 + e06a6a6 commit 600627d

1 file changed

Lines changed: 24 additions & 2 deletions

File tree

include/boost/math/tools/cubic_roots.hpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,33 @@
66
#define BOOST_MATH_TOOLS_CUBIC_ROOTS_HPP
77
#include <algorithm>
88
#include <array>
9+
#include <boost/math/special_functions/fpclassify.hpp>
910
#include <boost/math/special_functions/sign.hpp>
1011
#include <boost/math/tools/roots.hpp>
1112

1213
namespace boost::math::tools {
1314

15+
namespace detail {
16+
17+
// Orders finite roots ascending and moves NaN entries to the back.
18+
// Sorting NaNs is UB when using vanilla operator< (comparisons to NaN are always false),
19+
// so we need to provide our own sort function that pushes NaN to the end
20+
template <typename Real>
21+
bool roots_less(const Real& lhs, const Real& rhs)
22+
{
23+
if ((boost::math::isnan)(lhs))
24+
{
25+
return false;
26+
}
27+
if ((boost::math::isnan)(rhs))
28+
{
29+
return true;
30+
}
31+
return lhs < rhs;
32+
}
33+
34+
} // namespace detail
35+
1436
// Solves ax^3 + bx^2 + cx + d = 0.
1537
// Only returns the real roots, as types get weird for real coefficients and
1638
// complex roots. Follows Numerical Recipes, Chapter 5, section 6. NB: A better
@@ -55,7 +77,7 @@ std::array<Real, 3> cubic_roots(Real a, Real b, Real c, Real d) {
5577
roots[0] = x0;
5678
roots[1] = x1;
5779
roots[2] = 0;
58-
std::sort(roots.begin(), roots.end());
80+
std::sort(roots.begin(), roots.end(), detail::roots_less<Real>);
5981
return roots;
6082
}
6183
Real p = b / a;
@@ -115,7 +137,7 @@ std::array<Real, 3> cubic_roots(Real a, Real b, Real c, Real d) {
115137
}
116138
}
117139
}
118-
std::sort(roots.begin(), roots.end());
140+
std::sort(roots.begin(), roots.end(), detail::roots_less<Real>);
119141
return roots;
120142
}
121143

0 commit comments

Comments
 (0)