|
6 | 6 | #define BOOST_MATH_TOOLS_CUBIC_ROOTS_HPP |
7 | 7 | #include <algorithm> |
8 | 8 | #include <array> |
| 9 | +#include <boost/math/special_functions/fpclassify.hpp> |
9 | 10 | #include <boost/math/special_functions/sign.hpp> |
10 | 11 | #include <boost/math/tools/roots.hpp> |
11 | 12 |
|
12 | 13 | namespace boost::math::tools { |
13 | 14 |
|
| 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 | + |
14 | 36 | // Solves ax^3 + bx^2 + cx + d = 0. |
15 | 37 | // Only returns the real roots, as types get weird for real coefficients and |
16 | 38 | // 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) { |
55 | 77 | roots[0] = x0; |
56 | 78 | roots[1] = x1; |
57 | 79 | roots[2] = 0; |
58 | | - std::sort(roots.begin(), roots.end()); |
| 80 | + std::sort(roots.begin(), roots.end(), detail::roots_less<Real>); |
59 | 81 | return roots; |
60 | 82 | } |
61 | 83 | Real p = b / a; |
@@ -115,7 +137,7 @@ std::array<Real, 3> cubic_roots(Real a, Real b, Real c, Real d) { |
115 | 137 | } |
116 | 138 | } |
117 | 139 | } |
118 | | - std::sort(roots.begin(), roots.end()); |
| 140 | + std::sort(roots.begin(), roots.end(), detail::roots_less<Real>); |
119 | 141 | return roots; |
120 | 142 | } |
121 | 143 |
|
|
0 commit comments