QuadraticRealPolynomial.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import DeveloperError from "./DeveloperError.js";
  2. import CesiumMath from "./Math.js";
  3. /**
  4. * Defines functions for 2nd order polynomial functions of one variable with only real coefficients.
  5. *
  6. * @namespace QuadraticRealPolynomial
  7. */
  8. const QuadraticRealPolynomial = {};
  9. /**
  10. * Provides the discriminant of the quadratic equation from the supplied coefficients.
  11. *
  12. * @param {number} a The coefficient of the 2nd order monomial.
  13. * @param {number} b The coefficient of the 1st order monomial.
  14. * @param {number} c The coefficient of the 0th order monomial.
  15. * @returns {number} The value of the discriminant.
  16. */
  17. QuadraticRealPolynomial.computeDiscriminant = function (a, b, c) {
  18. //>>includeStart('debug', pragmas.debug);
  19. if (typeof a !== "number") {
  20. throw new DeveloperError("a is a required number.");
  21. }
  22. if (typeof b !== "number") {
  23. throw new DeveloperError("b is a required number.");
  24. }
  25. if (typeof c !== "number") {
  26. throw new DeveloperError("c is a required number.");
  27. }
  28. //>>includeEnd('debug');
  29. const discriminant = b * b - 4.0 * a * c;
  30. return discriminant;
  31. };
  32. function addWithCancellationCheck(left, right, tolerance) {
  33. const difference = left + right;
  34. if (
  35. CesiumMath.sign(left) !== CesiumMath.sign(right) &&
  36. Math.abs(difference / Math.max(Math.abs(left), Math.abs(right))) < tolerance
  37. ) {
  38. return 0.0;
  39. }
  40. return difference;
  41. }
  42. /**
  43. * Provides the real valued roots of the quadratic polynomial with the provided coefficients.
  44. *
  45. * @param {number} a The coefficient of the 2nd order monomial.
  46. * @param {number} b The coefficient of the 1st order monomial.
  47. * @param {number} c The coefficient of the 0th order monomial.
  48. * @returns {number[]} The real valued roots.
  49. */
  50. QuadraticRealPolynomial.computeRealRoots = function (a, b, c) {
  51. //>>includeStart('debug', pragmas.debug);
  52. if (typeof a !== "number") {
  53. throw new DeveloperError("a is a required number.");
  54. }
  55. if (typeof b !== "number") {
  56. throw new DeveloperError("b is a required number.");
  57. }
  58. if (typeof c !== "number") {
  59. throw new DeveloperError("c is a required number.");
  60. }
  61. //>>includeEnd('debug');
  62. let ratio;
  63. if (a === 0.0) {
  64. if (b === 0.0) {
  65. // Constant function: c = 0.
  66. return [];
  67. }
  68. // Linear function: b * x + c = 0.
  69. return [-c / b];
  70. } else if (b === 0.0) {
  71. if (c === 0.0) {
  72. // 2nd order monomial: a * x^2 = 0.
  73. return [0.0, 0.0];
  74. }
  75. const cMagnitude = Math.abs(c);
  76. const aMagnitude = Math.abs(a);
  77. if (
  78. cMagnitude < aMagnitude &&
  79. cMagnitude / aMagnitude < CesiumMath.EPSILON14
  80. ) {
  81. // c ~= 0.0.
  82. // 2nd order monomial: a * x^2 = 0.
  83. return [0.0, 0.0];
  84. } else if (
  85. cMagnitude > aMagnitude &&
  86. aMagnitude / cMagnitude < CesiumMath.EPSILON14
  87. ) {
  88. // a ~= 0.0.
  89. // Constant function: c = 0.
  90. return [];
  91. }
  92. // a * x^2 + c = 0
  93. ratio = -c / a;
  94. if (ratio < 0.0) {
  95. // Both roots are complex.
  96. return [];
  97. }
  98. // Both roots are real.
  99. const root = Math.sqrt(ratio);
  100. return [-root, root];
  101. } else if (c === 0.0) {
  102. // a * x^2 + b * x = 0
  103. ratio = -b / a;
  104. if (ratio < 0.0) {
  105. return [ratio, 0.0];
  106. }
  107. return [0.0, ratio];
  108. }
  109. // a * x^2 + b * x + c = 0
  110. const b2 = b * b;
  111. const four_ac = 4.0 * a * c;
  112. const radicand = addWithCancellationCheck(b2, -four_ac, CesiumMath.EPSILON14);
  113. if (radicand < 0.0) {
  114. // Both roots are complex.
  115. return [];
  116. }
  117. const q =
  118. -0.5 *
  119. addWithCancellationCheck(
  120. b,
  121. CesiumMath.sign(b) * Math.sqrt(radicand),
  122. CesiumMath.EPSILON14
  123. );
  124. if (b > 0.0) {
  125. return [q / a, c / q];
  126. }
  127. return [c / q, q / a];
  128. };
  129. export default QuadraticRealPolynomial;