ImathRoots.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. ///////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2002-2012, Industrial Light & Magic, a division of Lucas
  4. // Digital Ltd. LLC
  5. //
  6. // All rights reserved.
  7. //
  8. // Redistribution and use in source and binary forms, with or without
  9. // modification, are permitted provided that the following conditions are
  10. // met:
  11. // * Redistributions of source code must retain the above copyright
  12. // notice, this list of conditions and the following disclaimer.
  13. // * Redistributions in binary form must reproduce the above
  14. // copyright notice, this list of conditions and the following disclaimer
  15. // in the documentation and/or other materials provided with the
  16. // distribution.
  17. // * Neither the name of Industrial Light & Magic nor the names of
  18. // its contributors may be used to endorse or promote products derived
  19. // from this software without specific prior written permission.
  20. //
  21. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  24. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  25. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  26. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  27. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  28. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  29. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  30. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  31. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32. //
  33. ///////////////////////////////////////////////////////////////////////////
  34. #ifndef INCLUDED_IMATHROOTS_H
  35. #define INCLUDED_IMATHROOTS_H
  36. //---------------------------------------------------------------------
  37. //
  38. // Functions to solve linear, quadratic or cubic equations
  39. //
  40. //---------------------------------------------------------------------
  41. #include "ImathMath.h"
  42. #include "ImathNamespace.h"
  43. #include <complex>
  44. IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
  45. //--------------------------------------------------------------------------
  46. // Find the real solutions of a linear, quadratic or cubic equation:
  47. //
  48. // function equation solved
  49. //
  50. // solveLinear (a, b, x) a * x + b == 0
  51. // solveQuadratic (a, b, c, x) a * x*x + b * x + c == 0
  52. // solveNormalizedCubic (r, s, t, x) x*x*x + r * x*x + s * x + t == 0
  53. // solveCubic (a, b, c, d, x) a * x*x*x + b * x*x + c * x + d == 0
  54. //
  55. // Return value:
  56. //
  57. // 3 three real solutions, stored in x[0], x[1] and x[2]
  58. // 2 two real solutions, stored in x[0] and x[1]
  59. // 1 one real solution, stored in x[1]
  60. // 0 no real solutions
  61. // -1 all real numbers are solutions
  62. //
  63. // Notes:
  64. //
  65. // * It is possible that an equation has real solutions, but that the
  66. // solutions (or some intermediate result) are not representable.
  67. // In this case, either some of the solutions returned are invalid
  68. // (nan or infinity), or, if floating-point exceptions have been
  69. // enabled with Iex::mathExcOn(), an Iex::MathExc exception is
  70. // thrown.
  71. //
  72. // * Cubic equations are solved using Cardano's Formula; even though
  73. // only real solutions are produced, some intermediate results are
  74. // complex (std::complex<T>).
  75. //
  76. //--------------------------------------------------------------------------
  77. template <class T> int solveLinear (T a, T b, T &x);
  78. template <class T> int solveQuadratic (T a, T b, T c, T x[2]);
  79. template <class T> int solveNormalizedCubic (T r, T s, T t, T x[3]);
  80. template <class T> int solveCubic (T a, T b, T c, T d, T x[3]);
  81. //---------------
  82. // Implementation
  83. //---------------
  84. template <class T>
  85. int
  86. solveLinear (T a, T b, T &x)
  87. {
  88. if (a != 0)
  89. {
  90. x = -b / a;
  91. return 1;
  92. }
  93. else if (b != 0)
  94. {
  95. return 0;
  96. }
  97. else
  98. {
  99. return -1;
  100. }
  101. }
  102. template <class T>
  103. int
  104. solveQuadratic (T a, T b, T c, T x[2])
  105. {
  106. if (a == 0)
  107. {
  108. return solveLinear (b, c, x[0]);
  109. }
  110. else
  111. {
  112. T D = b * b - 4 * a * c;
  113. if (D > 0)
  114. {
  115. T s = Math<T>::sqrt (D);
  116. T q = -(b + (b > 0 ? 1 : -1) * s) / T(2);
  117. x[0] = q / a;
  118. x[1] = c / q;
  119. return 2;
  120. }
  121. if (D == 0)
  122. {
  123. x[0] = -b / (2 * a);
  124. return 1;
  125. }
  126. else
  127. {
  128. return 0;
  129. }
  130. }
  131. }
  132. template <class T>
  133. int
  134. solveNormalizedCubic (T r, T s, T t, T x[3])
  135. {
  136. T p = (3 * s - r * r) / 3;
  137. T q = 2 * r * r * r / 27 - r * s / 3 + t;
  138. T p3 = p / 3;
  139. T q2 = q / 2;
  140. T D = p3 * p3 * p3 + q2 * q2;
  141. if (D == 0 && p3 == 0)
  142. {
  143. x[0] = -r / 3;
  144. x[1] = -r / 3;
  145. x[2] = -r / 3;
  146. return 1;
  147. }
  148. std::complex<T> u = std::pow (-q / 2 + std::sqrt (std::complex<T> (D)),
  149. T (1) / T (3));
  150. std::complex<T> v = -p / (T (3) * u);
  151. const T sqrt3 = T (1.73205080756887729352744634150587); // enough digits
  152. // for long double
  153. std::complex<T> y0 (u + v);
  154. std::complex<T> y1 (-(u + v) / T (2) +
  155. (u - v) / T (2) * std::complex<T> (0, sqrt3));
  156. std::complex<T> y2 (-(u + v) / T (2) -
  157. (u - v) / T (2) * std::complex<T> (0, sqrt3));
  158. if (D > 0)
  159. {
  160. x[0] = y0.real() - r / 3;
  161. return 1;
  162. }
  163. else if (D == 0)
  164. {
  165. x[0] = y0.real() - r / 3;
  166. x[1] = y1.real() - r / 3;
  167. return 2;
  168. }
  169. else
  170. {
  171. x[0] = y0.real() - r / 3;
  172. x[1] = y1.real() - r / 3;
  173. x[2] = y2.real() - r / 3;
  174. return 3;
  175. }
  176. }
  177. template <class T>
  178. int
  179. solveCubic (T a, T b, T c, T d, T x[3])
  180. {
  181. if (a == 0)
  182. {
  183. return solveQuadratic (b, c, d, x);
  184. }
  185. else
  186. {
  187. return solveNormalizedCubic (b / a, c / a, d / a, x);
  188. }
  189. }
  190. IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
  191. #endif // INCLUDED_IMATHROOTS_H