CubicRealPolynomial.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. import DeveloperError from './DeveloperError.js';
  2. import QuadraticRealPolynomial from './QuadraticRealPolynomial.js';
  3. /**
  4. * Defines functions for 3rd order polynomial functions of one variable with only real coefficients.
  5. *
  6. * @exports CubicRealPolynomial
  7. */
  8. var CubicRealPolynomial = {};
  9. /**
  10. * Provides the discriminant of the cubic equation from the supplied coefficients.
  11. *
  12. * @param {Number} a The coefficient of the 3rd order monomial.
  13. * @param {Number} b The coefficient of the 2nd order monomial.
  14. * @param {Number} c The coefficient of the 1st order monomial.
  15. * @param {Number} d The coefficient of the 0th order monomial.
  16. * @returns {Number} The value of the discriminant.
  17. */
  18. CubicRealPolynomial.computeDiscriminant = function(a, b, c, d) {
  19. //>>includeStart('debug', pragmas.debug);
  20. if (typeof a !== 'number') {
  21. throw new DeveloperError('a is a required number.');
  22. }
  23. if (typeof b !== 'number') {
  24. throw new DeveloperError('b is a required number.');
  25. }
  26. if (typeof c !== 'number') {
  27. throw new DeveloperError('c is a required number.');
  28. }
  29. if (typeof d !== 'number') {
  30. throw new DeveloperError('d is a required number.');
  31. }
  32. //>>includeEnd('debug');
  33. var a2 = a * a;
  34. var b2 = b * b;
  35. var c2 = c * c;
  36. var d2 = d * d;
  37. var discriminant = 18.0 * a * b * c * d + b2 * c2 - 27.0 * a2 * d2 - 4.0 * (a * c2 * c + b2 * b * d);
  38. return discriminant;
  39. };
  40. function computeRealRoots(a, b, c, d) {
  41. var A = a;
  42. var B = b / 3.0;
  43. var C = c / 3.0;
  44. var D = d;
  45. var AC = A * C;
  46. var BD = B * D;
  47. var B2 = B * B;
  48. var C2 = C * C;
  49. var delta1 = A * C - B2;
  50. var delta2 = A * D - B * C;
  51. var delta3 = B * D - C2;
  52. var discriminant = 4.0 * delta1 * delta3 - delta2 * delta2;
  53. var temp;
  54. var temp1;
  55. if (discriminant < 0.0) {
  56. var ABar;
  57. var CBar;
  58. var DBar;
  59. if (B2 * BD >= AC * C2) {
  60. ABar = A;
  61. CBar = delta1;
  62. DBar = -2.0 * B * delta1 + A * delta2;
  63. } else {
  64. ABar = D;
  65. CBar = delta3;
  66. DBar = -D * delta2 + 2.0 * C * delta3;
  67. }
  68. var s = (DBar < 0.0) ? -1.0 : 1.0; // This is not Math.Sign()!
  69. var temp0 = -s * Math.abs(ABar) * Math.sqrt(-discriminant);
  70. temp1 = -DBar + temp0;
  71. var x = temp1 / 2.0;
  72. var p = x < 0.0 ? -Math.pow(-x, 1.0 / 3.0) : Math.pow(x, 1.0 / 3.0);
  73. var q = (temp1 === temp0) ? -p : -CBar / p;
  74. temp = (CBar <= 0.0) ? p + q : -DBar / (p * p + q * q + CBar);
  75. if (B2 * BD >= AC * C2) {
  76. return [(temp - B) / A];
  77. }
  78. return [-D / (temp + C)];
  79. }
  80. var CBarA = delta1;
  81. var DBarA = -2.0 * B * delta1 + A * delta2;
  82. var CBarD = delta3;
  83. var DBarD = -D * delta2 + 2.0 * C * delta3;
  84. var squareRootOfDiscriminant = Math.sqrt(discriminant);
  85. var halfSquareRootOf3 = Math.sqrt(3.0) / 2.0;
  86. var theta = Math.abs(Math.atan2(A * squareRootOfDiscriminant, -DBarA) / 3.0);
  87. temp = 2.0 * Math.sqrt(-CBarA);
  88. var cosine = Math.cos(theta);
  89. temp1 = temp * cosine;
  90. var temp3 = temp * (-cosine / 2.0 - halfSquareRootOf3 * Math.sin(theta));
  91. var numeratorLarge = (temp1 + temp3 > 2.0 * B) ? temp1 - B : temp3 - B;
  92. var denominatorLarge = A;
  93. var root1 = numeratorLarge / denominatorLarge;
  94. theta = Math.abs(Math.atan2(D * squareRootOfDiscriminant, -DBarD) / 3.0);
  95. temp = 2.0 * Math.sqrt(-CBarD);
  96. cosine = Math.cos(theta);
  97. temp1 = temp * cosine;
  98. temp3 = temp * (-cosine / 2.0 - halfSquareRootOf3 * Math.sin(theta));
  99. var numeratorSmall = -D;
  100. var denominatorSmall = (temp1 + temp3 < 2.0 * C) ? temp1 + C : temp3 + C;
  101. var root3 = numeratorSmall / denominatorSmall;
  102. var E = denominatorLarge * denominatorSmall;
  103. var F = -numeratorLarge * denominatorSmall - denominatorLarge * numeratorSmall;
  104. var G = numeratorLarge * numeratorSmall;
  105. var root2 = (C * F - B * G) / (-B * F + C * E);
  106. if (root1 <= root2) {
  107. if (root1 <= root3) {
  108. if (root2 <= root3) {
  109. return [root1, root2, root3];
  110. }
  111. return [root1, root3, root2];
  112. }
  113. return [root3, root1, root2];
  114. }
  115. if (root1 <= root3) {
  116. return [root2, root1, root3];
  117. }
  118. if (root2 <= root3) {
  119. return [root2, root3, root1];
  120. }
  121. return [root3, root2, root1];
  122. }
  123. /**
  124. * Provides the real valued roots of the cubic polynomial with the provided coefficients.
  125. *
  126. * @param {Number} a The coefficient of the 3rd order monomial.
  127. * @param {Number} b The coefficient of the 2nd order monomial.
  128. * @param {Number} c The coefficient of the 1st order monomial.
  129. * @param {Number} d The coefficient of the 0th order monomial.
  130. * @returns {Number[]} The real valued roots.
  131. */
  132. CubicRealPolynomial.computeRealRoots = function(a, b, c, d) {
  133. //>>includeStart('debug', pragmas.debug);
  134. if (typeof a !== 'number') {
  135. throw new DeveloperError('a is a required number.');
  136. }
  137. if (typeof b !== 'number') {
  138. throw new DeveloperError('b is a required number.');
  139. }
  140. if (typeof c !== 'number') {
  141. throw new DeveloperError('c is a required number.');
  142. }
  143. if (typeof d !== 'number') {
  144. throw new DeveloperError('d is a required number.');
  145. }
  146. //>>includeEnd('debug');
  147. var roots;
  148. var ratio;
  149. if (a === 0.0) {
  150. // Quadratic function: b * x^2 + c * x + d = 0.
  151. return QuadraticRealPolynomial.computeRealRoots(b, c, d);
  152. } else if (b === 0.0) {
  153. if (c === 0.0) {
  154. if (d === 0.0) {
  155. // 3rd order monomial: a * x^3 = 0.
  156. return [0.0, 0.0, 0.0];
  157. }
  158. // a * x^3 + d = 0
  159. ratio = -d / a;
  160. var root = (ratio < 0.0) ? -Math.pow(-ratio, 1.0 / 3.0) : Math.pow(ratio, 1.0 / 3.0);
  161. return [root, root, root];
  162. } else if (d === 0.0) {
  163. // x * (a * x^2 + c) = 0.
  164. roots = QuadraticRealPolynomial.computeRealRoots(a, 0, c);
  165. // Return the roots in ascending order.
  166. if (roots.Length === 0) {
  167. return [0.0];
  168. }
  169. return [roots[0], 0.0, roots[1]];
  170. }
  171. // Deflated cubic polynomial: a * x^3 + c * x + d= 0.
  172. return computeRealRoots(a, 0, c, d);
  173. } else if (c === 0.0) {
  174. if (d === 0.0) {
  175. // x^2 * (a * x + b) = 0.
  176. ratio = -b / a;
  177. if (ratio < 0.0) {
  178. return [ratio, 0.0, 0.0];
  179. }
  180. return [0.0, 0.0, ratio];
  181. }
  182. // a * x^3 + b * x^2 + d = 0.
  183. return computeRealRoots(a, b, 0, d);
  184. } else if (d === 0.0) {
  185. // x * (a * x^2 + b * x + c) = 0
  186. roots = QuadraticRealPolynomial.computeRealRoots(a, b, c);
  187. // Return the roots in ascending order.
  188. if (roots.length === 0) {
  189. return [0.0];
  190. } else if (roots[1] <= 0.0) {
  191. return [roots[0], roots[1], 0.0];
  192. } else if (roots[0] >= 0.0) {
  193. return [0.0, roots[0], roots[1]];
  194. }
  195. return [roots[0], 0.0, roots[1]];
  196. }
  197. return computeRealRoots(a, b, c, d);
  198. };
  199. export default CubicRealPolynomial;