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