12#include "detray/definitions/algebra.hpp"
13#include "detray/definitions/containers.hpp"
14#include "detray/definitions/detail/qualifiers.hpp"
15#include "detray/definitions/math.hpp"
16#include "detray/utils/invalid_values.hpp"
21namespace detray::detail {
23template <concepts::scalar scalar_t,
typename =
void>
31template <concepts::scalar scalar_t>
32 requires std::is_arithmetic_v<scalar_t>
33class quadratic_equation<scalar_t> {
35 quadratic_equation() =
delete;
45 const scalar_t a,
const scalar_t b,
const scalar_t c,
46 const scalar_t tolerance = std::numeric_limits<scalar_t>::epsilon()) {
48 if (math::fabs(a) <= tolerance) {
49 if (math::fabs(b) <= tolerance) {
56 const scalar_t discriminant{b * b - 4.f * a * c};
58 if (discriminant > tolerance) {
60 const scalar_t q{-0.5f *
61 (b + math::copysign(math::sqrt(discriminant), b))};
62 m_values = {q / a, c / q};
64 if (m_values[0] > m_values[1]) {
65 m_values = {m_values[1], m_values[0]};
69 else if (discriminant >= 0.f) {
71 m_values[0] = -0.5f * b / a;
81 constexpr int solutions()
const {
return m_solutions; }
83 constexpr scalar_t
smaller()
const {
return m_values[0]; }
85 constexpr scalar_t
larger()
const {
return m_values[1]; }
93 detail::invalid_value<scalar_t>()};
101template <concepts::scalar scalar_t>
102 requires(!std::is_arithmetic_v<scalar_t>)
115 const scalar_t &tolerance = 1e-6f) {
117 auto one_sol = (math::fabs(a) <= tolerance);
118 m_solutions(one_sol) = 1.f;
119 m_values[0] = -c / b;
122 if (detray::detail::all_of(one_sol)) {
126 const scalar_t discriminant = b * b - (4.f * a) * c;
128 const auto two_sol = (discriminant > tolerance);
129 one_sol = !two_sol && (discriminant >= 0.f);
132 if (detray::detail::any_of(two_sol)) {
134 m_solutions.setZeroInverted(two_sol);
137 -0.5f * (b + math::copysign(math::sqrt(discriminant), b));
139 scalar_t first = q / a;
140 scalar_t second = c / q;
141 first.setZeroInverted(two_sol);
142 second.setZeroInverted(two_sol);
145 const auto do_swap = (second < first);
146 if (detray::detail::all_of(do_swap)) {
147 m_values = {second, first};
148 }
else if (detray::detail::none_of(do_swap)) {
149 m_values = {first, second};
151 const auto tmp = second;
152 second(do_swap) = first;
153 first(do_swap) = tmp;
154 m_values = {first, second};
159 if (detray::detail::any_of(one_sol)) {
161 scalar_t result = -0.5f * b / a;
162 sol.setZeroInverted(one_sol);
163 result.setZeroInverted(one_sol);
166 m_values[0] += result;
175 constexpr const auto &
solutions()
const {
return m_solutions; }
177 constexpr const scalar_t &
smaller()
const {
return m_values[0]; }
179 constexpr const scalar_t &
larger()
const {
return m_values[1]; }
185 scalar_t m_solutions = 0.f;
188 static_cast<scalar_t
>(0.f)};
192quadratic_equation(
const S a,
const S &b,
const S &c,
const S &tolerance)
193 -> quadratic_equation<S>;
constexpr scalar_t smaller() const
Definition quadratic_equation.hpp:83
constexpr scalar_t larger() const
Definition quadratic_equation.hpp:85
constexpr const scalar_t & larger() const
Definition quadratic_equation.hpp:179
constexpr const scalar_t & smaller() const
Definition quadratic_equation.hpp:177
constexpr quadratic_equation(const scalar_t &a, const scalar_t &b, const scalar_t &c, const scalar_t &tolerance=1e-6f)
Solve the equation a*x^2 + b*x + c = 0 for SIMD coefficients.
Definition quadratic_equation.hpp:113
constexpr int solutions() const
Getters for the solution(s).
Definition quadratic_equation.hpp:81
constexpr const auto & solutions() const
Getters for the solution(s).
Definition quadratic_equation.hpp:175
constexpr quadratic_equation(const scalar_t a, const scalar_t b, const scalar_t c, const scalar_t tolerance=std::numeric_limits< scalar_t >::epsilon())
Solve the equation a*x^2 + b*x + c = 0 for arithmetic coefficients.
Definition quadratic_equation.hpp:44
Definition quadratic_equation.hpp:24
std::array< value_t, kDIM > darray
Fixed-size array container.
Definition containers.hpp:30