HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ImathRoots.h
Go to the documentation of this file.
1 //
2 // SPDX-License-Identifier: BSD-3-Clause
3 // Copyright Contributors to the OpenEXR Project.
4 //
5 
6 //
7 // Functions to solve linear, quadratic or cubic equations
8 //
9 // Note: It is possible that an equation has real solutions, but that
10 // the solutions (or some intermediate result) are not representable.
11 // In this case, either some of the solutions returned are invalid
12 // (nan or infinity), or, if floating-point exceptions have been
13 // enabled, an exception is thrown.
14 //
15 
16 #ifndef INCLUDED_IMATHROOTS_H
17 #define INCLUDED_IMATHROOTS_H
18 
19 #include "ImathMath.h"
20 #include "ImathNamespace.h"
21 #include <complex>
22 
23 /// @cond Doxygen_Suppress
24 
25 // If CUDA or HIP (AMD's Heterogeneous-computing Interface for
26 // Portability), use the thrust complex library
27 #if defined(__CUDACC__) || defined(__HIP__)
28 # include <thrust/complex.h>
29 # define COMPLEX_NAMESPACE thrust
30 #else
31 # define COMPLEX_NAMESPACE std
32 #endif
33 
34 /// @endcond
35 
36 IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
37 
38 ///
39 /// Solve for x in the linear equation:
40 ///
41 /// a * x + b == 0
42 ///
43 /// @return 1 if the equation has a solution, 0 if there is no
44 /// solution, and -1 if all real numbers are solutions.
45 template <class T>
46 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 int solveLinear (T a, T b, T& x);
47 
48 ///
49 /// Solve for x in the quadratic equation:
50 ///
51 /// a * x*x + b * x + c == 0
52 ///
53 /// @return 2 if the equation has two solutions, 1 if the equation has
54 /// a single solution, 0 if there is no solution, and -1 if all real
55 /// numbers are solutions.
56 template <class T>
57 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 int solveQuadratic (T a, T b, T c, T x[2]);
58 template <class T>
59 
60 ///
61 /// Solve for x in the normalized cubic equation:
62 ///
63 /// x*x*x + r * x*x + s * x + t == 0
64 ///
65 /// The equation is solved using Cardano's Formula; even though only
66 /// real solutions are produced, some intermediate results are complex
67 /// (std::complex<T>).
68 ///
69 /// @return 0 if there is no solution, and -1 if all real
70 /// numbers are solutions, otherwise return the number of solutions.
71 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 int
72 solveNormalizedCubic (T r, T s, T t, T x[3]);
73 
74 ///
75 /// Solve for x in the cubic equation:
76 ///
77 /// a * x*x*x + b * x*x + c * x + d == 0
78 ///
79 /// The equation is solved using Cardano's Formula; even though only
80 /// real solutions are produced, some intermediate results are complex
81 /// (std::complex<T>).
82 ///
83 /// @return 0 if there is no solution, and -1 if all real
84 /// numbers are solutions, otherwise return the number of solutions.
85 template <class T>
86 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 int solveCubic (T a, T b, T c, T d, T x[3]);
87 
88 //---------------
89 // Implementation
90 //---------------
91 
92 template <class T>
93 IMATH_CONSTEXPR14 int
94 solveLinear (T a, T b, T& x)
95 {
96  if (a != 0)
97  {
98  x = -b / a;
99  return 1;
100  }
101  else if (b != 0)
102  {
103  return 0;
104  }
105  else
106  {
107  return -1;
108  }
109 }
110 
111 template <class T>
112 IMATH_CONSTEXPR14 int
113 solveQuadratic (T a, T b, T c, T x[2])
114 {
115  if (a == 0) { return solveLinear (b, c, x[0]); }
116  else
117  {
118  T D = b * b - 4 * a * c;
119 
120  if (D > 0)
121  {
122  T s = std::sqrt (D);
123  T q = -(b + (b > 0 ? 1 : -1) * s) / T (2);
124 
125  x[0] = q / a;
126  x[1] = c / q;
127  return 2;
128  }
129  if (D == 0)
130  {
131  x[0] = -b / (2 * a);
132  return 1;
133  }
134  else
135  {
136  return 0;
137  }
138  }
139 }
140 
141 template <class T>
142 IMATH_CONSTEXPR14 int
143 solveNormalizedCubic (T r, T s, T t, T x[3])
144 {
145  T p = (3 * s - r * r) / 3;
146  T q = 2 * r * r * r / 27 - r * s / 3 + t;
147  T p3 = p / 3;
148  T q2 = q / 2;
149  T D = p3 * p3 * p3 + q2 * q2;
150 
151  if (D == 0 && p3 == 0)
152  {
153  x[0] = -r / 3;
154  x[1] = -r / 3;
155  x[2] = -r / 3;
156  return 1;
157  }
158 
159  if (D > 0)
160  {
161  auto real_root = [] (T a, T x) -> T {
162  T sign = std::copysign (T (1), a);
163  return sign * std::pow (sign * a, T (1) / x);
164  };
165 
166  T u = real_root (-q / 2 + std::sqrt (D), 3);
167  T v = -p / (T (3) * u);
168 
169  x[0] = u + v - r / 3;
170  return 1;
171  }
172 
173  namespace CN = COMPLEX_NAMESPACE;
174  CN::complex<T> u =
175  CN::pow (-q / 2 + CN::sqrt (CN::complex<T> (D)), T (1) / T (3));
176  CN::complex<T> v = -p / (T (3) * u);
177 
178  const T sqrt3 = T (1.73205080756887729352744634150587); // enough digits
179  // for long double
180  CN::complex<T> y0 (u + v);
181  CN::complex<T> y1 (
182  -(u + v) / T (2) + (u - v) / T (2) * CN::complex<T> (0, sqrt3));
183  CN::complex<T> y2 (
184  -(u + v) / T (2) - (u - v) / T (2) * CN::complex<T> (0, sqrt3));
185 
186  if (D == 0)
187  {
188  x[0] = y0.real () - r / 3;
189  x[1] = y1.real () - r / 3;
190  return 2;
191  }
192  else
193  {
194  x[0] = y0.real () - r / 3;
195  x[1] = y1.real () - r / 3;
196  x[2] = y2.real () - r / 3;
197  return 3;
198  }
199 }
200 
201 template <class T>
202 IMATH_CONSTEXPR14 int
203 solveCubic (T a, T b, T c, T d, T x[3])
204 {
205  if (a == 0) { return solveQuadratic (b, c, d, x); }
206  else
207  {
208  return solveNormalizedCubic (b / a, c / a, d / a, x);
209  }
210 }
211 
212 IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
213 
214 #endif // INCLUDED_IMATHROOTS_H
IMATH_HOSTDEVICE IMATH_CONSTEXPR14 int solveCubic(T a, T b, T c, T d, T x[3])
Definition: ImathRoots.h:203
const GLdouble * v
Definition: glcorearb.h:837
vfloat4 sqrt(const vfloat4 &a)
Definition: simd.h:7694
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1222
GLdouble s
Definition: glad.h:3009
GLdouble GLdouble GLdouble q
Definition: glad.h:2445
#define IMATH_HOSTDEVICE
Definition: ImathConfig.h:108
ImageBuf OIIO_API pow(const ImageBuf &A, cspan< float > B, ROI roi={}, int nthreads=0)
GLdouble y1
Definition: glad.h:2349
IMATH_INTERNAL_NAMESPACE_HEADER_ENTER IMATH_HOSTDEVICE IMATH_CONSTEXPR14 int solveLinear(T a, T b, T &x)
Definition: ImathRoots.h:94
IMATH_HOSTDEVICE constexpr int sign(T a) IMATH_NOEXCEPT
Definition: ImathFun.h:33
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1222
GLint GLenum GLint x
Definition: glcorearb.h:409
GLdouble t
Definition: glad.h:2397
IMATH_HOSTDEVICE IMATH_CONSTEXPR14 int solveNormalizedCubic(T r, T s, T t, T x[3])
Definition: ImathRoots.h:143
GLboolean r
Definition: glcorearb.h:1222
GLdouble GLdouble GLdouble y2
Definition: glad.h:2349
IMATH_HOSTDEVICE IMATH_CONSTEXPR14 int solveQuadratic(T a, T b, T c, T x[2])
Definition: ImathRoots.h:113