Description
Motivation
Equations such as
The formula above suffers from issues such as cancellation errors in the determinant calculation and indeterminacy when
- Numerically stable method for solving quadratic equations | Stack Exchange
- Numerically Stable Method for Solving Quadratic Equations (PDF, 28 KB)
- Numerically stable algorithm for solving the quadratic equation when 𝑎 is very small or 0 | Math StackExchange
- Quadratic equation - Avoiding Loss of significance | Wikipedia
- Nonweiler, T. R. (1968). Algorithm 326: Roots of low-order polynomial equations. Communications of the ACM, 11(4), 269-270. (PDF, 481 KB)
- On the Cost of Floating-Point Computation Without Extra-Precise Arithmetic | W. Kahan, 2004 (see routine
qdrtc
) - HOW DO YOU SOLVE A QUADRATIC EQUATION? BY GEORGE E. FORSYTHE, Technical Report No. CS40, 1966
Prior Art
MATLAB: roots
Boost: quadratic_roots
Julia: Polynomials.roots
NAG: quadratic_real
and quadratic_complex
Additional Information
One possible interface might look as follows:
interface quadratic_roots
subroutine squadratic_roots(a,b,c,x0,x1)
import sp
real(sp), intent(in) :: a, b, c
real(sp), intent(out) :: x0, x1
end subroutine
subroutine dquadratic_roots(a,b,c,x0,x1)
import dp
real(dp), intent(in) :: a, b, c
real(dp), intent(out) :: x0, x1
end subroutine
subroutine cquadratic_roots(a,b,c,x0,x1)
import sp
complex(sp), intent(in) :: a, b, c
complex(sp), intent(out) :: x0, x1
end subroutine
subroutine zquadratic_roots(a,b,c,x0,x1)
import dp
complex(dp), intent(in) :: a, b, c
complex(dp), intent(out) :: x0, x1
end subroutine
end interface
If bind(C)
were allowed, an implementation based upon Boost C++ libraries could look as follows:
#include <boost/math/tools/roots.hpp>
#define NAME(name,kind) kind ## name
#define QUADRATIC_ROOTS(kind,T) \
void NAME(quadratic_roots,kind) \
(const T* a, const T* b, const T* c, T* x0, T* x1) { \
auto [r0, r1] = boost::math::tools::quadratic_roots(*a,*b,*c); \
*x0 = r0; \
*x1 = r1; \
};
#define FOR_EACH_DATA_TYPE(X) \
X(s,float) \
X(d,double) \
X(c,std::complex<float>) \
X(z,std::complex<double>)
extern "C" {
FOR_EACH_DATA_TYPE(QUADRATIC_ROOTS)
}