OpenWalnut  1.5.0dev
WPolynomialEquationSolvers.h
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #ifndef WPOLYNOMIALEQUATIONSOLVERS_H
26 #define WPOLYNOMIALEQUATIONSOLVERS_H
27 
28 #include <complex>
29 #include <sstream>
30 #include <utility>
31 
32 #include "../exceptions/WEquationHasNoRoots.h"
33 #include "../WLimits.h"
34 
35 
36 /**
37  * Solves a quadratic equation: ax^2 + bx + c = 0 where a,b,c are real coefficient.
38  *
39  * \param a first coefficient
40  * \param b second coefficient
41  * \param c remainder
42  *
43  * \throw WEquationHasNoRoots In case there are no roots for this equation.
44  *
45  * \return Solutions to the equation above as complex numbers. If only one solution exists both
46  * complex numbers are the same!
47  */
48 template< typename T > typename std::pair< typename std::complex< T >, typename std::complex< T > > solveRealQuadraticEquation( T a, T b, T c );
49 
50 
51 
52 template< typename T >
53 inline typename std::pair< typename std::complex< T >, typename std::complex< T > > solveRealQuadraticEquation( T a, T b, T c )
54 {
55  typename std::pair< typename std::complex< T >, typename std::complex< T > > result( std::complex< T >( 0.0, 0.0 ), std::complex< T >( 0.0, 0.0 ) ); // NOLINT line length
56  if( a != 1.0 ) // normalize
57  {
58  if( std::abs( a ) <= wlimits::DBL_EPS ) // a ≃ 0.0
59  {
60  if( std::abs( b ) <= wlimits::DBL_EPS ) // b ≃ 0.0
61  {
62  if( std::abs( c ) > wlimits::DBL_EPS ) // there is no solution
63  {
64  std::stringstream ss;
65  ss << "The equation: " << a << "x^2 + " << b << "x + " << c << " = 0.0 has no solutions!";
66  throw WEquationHasNoRoots( ss.str() );
67  }
68  else // all coefficents are zero so we return 0.0 as a solution
69  {
70  return result;
71  }
72  }
73  else // Note equation degrades to linear equation:
74  {
75  result.first = std::complex< T >( -c / b, 0.0 );
76  result.second = result.first;
77  return result;
78  }
79  }
80  else
81  {
82  b /= a;
83  c /= a;
84  a = 1.0;
85  }
86  }
87 
88  // equation is in normal form
89  double discriminant = b * b - 4.0 * c;
90  if( discriminant < 0.0 )
91  {
92  result.first = std::complex< T >( -b / 2.0, std::sqrt( std::abs( discriminant ) ) / 2.0 );
93  result.second = std::complex< T >( -b / 2.0, -std::sqrt( std::abs( discriminant ) ) / 2.0 );
94  }
95  else if( discriminant > 0.0 )
96  {
97  result.first = std::complex< T >( -b / 2.0 + std::sqrt( discriminant ) / 2.0, 0.0 );
98  result.second = std::complex< T >( -b / 2.0 - std::sqrt( discriminant ) / 2.0 , 0.0 );
99  }
100  else // discriminant ≃ 0.0
101  {
102  // NOTE: if b==-0.0 and discriminant==0.0 then result.first and result.second would be different. To prevent this we check if b ≃ 0.0
103  if( std::abs( b ) <= wlimits::DBL_EPS ) // b ≃ 0.0
104  {
105  result.first = std::complex< T >( 0.0, 0.0 );
106  result.second = result.first;
107  }
108  else
109  {
110  result.first = std::complex< T >( -b / 2, 0.0 );
111  result.second = result.first;
112  }
113  }
114  return result;
115 }
116 
117 #endif // WPOLYNOMIALEQUATIONSOLVERS_H
Indicates invalid element access of a container.
const double DBL_EPS
Smallest double such: 1.0 + DBL_EPS == 1.0 is still true.
Definition: WLimits.cpp:46