mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-01 02:38:43 -05:00
Simplify Numerical.solveCubic() code by introducing evaluate() closure.
This commit is contained in:
parent
9d6aab3802
commit
da78e837a1
1 changed files with 29 additions and 30 deletions
|
@ -99,12 +99,14 @@ var Numerical = new function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNormalizationFactor() {
|
function getNormalizationFactor() {
|
||||||
var max = Math.max.apply(Math, arguments);
|
|
||||||
// Normalize coefficients à la Jenkins & Traub's RPOLY.
|
// Normalize coefficients à la Jenkins & Traub's RPOLY.
|
||||||
// Normalization is done by scaling coefficients with a power of 2, so
|
// Normalization is done by scaling coefficients with a power of 2, so
|
||||||
// that all the bits in the mantissa remain unchanged.
|
// that all the bits in the mantissa remain unchanged.
|
||||||
return max && (max < 1e-8 || max > 1e8)
|
// Use the infinity norm (max(sum(abs(a)…)) to determine the appropriate
|
||||||
? pow(2, -Math.round(log2(max)))
|
// scale factor. See @hkrish in #1087#issuecomment-231526156
|
||||||
|
var norm = Math.max.apply(Math, arguments);
|
||||||
|
return norm && (norm < 1e-8 || norm > 1e8)
|
||||||
|
? pow(2, -Math.round(log2(norm)))
|
||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,13 +342,24 @@ var Numerical = new function() {
|
||||||
*/
|
*/
|
||||||
solveCubic: function(a, b, c, d, roots, min, max) {
|
solveCubic: function(a, b, c, d, roots, min, max) {
|
||||||
var f = getNormalizationFactor(abs(a), abs(b), abs(c), abs(d)),
|
var f = getNormalizationFactor(abs(a), abs(b), abs(c), abs(d)),
|
||||||
x, b1, c2;
|
x, b1, c2, qd, q;
|
||||||
if (f) {
|
if (f) {
|
||||||
a *= f;
|
a *= f;
|
||||||
b *= f;
|
b *= f;
|
||||||
c *= f;
|
c *= f;
|
||||||
d *= f;
|
d *= f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function evaluate(x0) {
|
||||||
|
x = x0;
|
||||||
|
// Evaluate q, q', b1 and c2 at x
|
||||||
|
var tmp = a * x;
|
||||||
|
b1 = tmp + b;
|
||||||
|
c2 = b1 * x + c;
|
||||||
|
qd = (tmp + b1) * x + c2;
|
||||||
|
q = c2 * x + d;
|
||||||
|
}
|
||||||
|
|
||||||
// If a or d is zero, we only need to solve a quadratic, so we set
|
// If a or d is zero, we only need to solve a quadratic, so we set
|
||||||
// the coefficients appropriately.
|
// the coefficients appropriately.
|
||||||
if (abs(a) < EPSILON) {
|
if (abs(a) < EPSILON) {
|
||||||
|
@ -359,38 +372,24 @@ var Numerical = new function() {
|
||||||
c2 = c;
|
c2 = c;
|
||||||
x = 0;
|
x = 0;
|
||||||
} else {
|
} else {
|
||||||
var ec = 1 + MACHINE_EPSILON, // 1.000...002
|
|
||||||
x0, q, qd, t, r, s, tmp;
|
|
||||||
// Here onwards we iterate for the leftmost root. Proceed to
|
// Here onwards we iterate for the leftmost root. Proceed to
|
||||||
// deflate the cubic into a quadratic (as a side effect to the
|
// deflate the cubic into a quadratic (as a side effect to the
|
||||||
// iteration) and solve the quadratic.
|
// iteration) and solve the quadratic.
|
||||||
x = -(b / a) / 3;
|
evaluate(-(b / a) / 3);
|
||||||
// Evaluate q, q', b1 and c2 at x
|
|
||||||
tmp = a * x;
|
|
||||||
b1 = tmp + b;
|
|
||||||
c2 = b1 * x + c;
|
|
||||||
qd = (tmp + b1) * x + c2;
|
|
||||||
q = c2 * x + d;
|
|
||||||
// Get a good initial approximation.
|
// Get a good initial approximation.
|
||||||
t = q / a;
|
var t = q / a,
|
||||||
r = pow(abs(t), 1/3);
|
r = pow(abs(t), 1/3),
|
||||||
s = t < 0 ? -1 : 1;
|
s = t < 0 ? -1 : 1,
|
||||||
t = -qd / a;
|
td = -qd / a,
|
||||||
// See Kahan's notes on why 1.324718*... works.
|
// See Kahan's notes on why 1.324718*... works.
|
||||||
r = t > 0 ? 1.324717957244746 * Math.max(r, sqrt(t)) : r;
|
rd = td > 0 ? 1.324717957244746 * Math.max(r, sqrt(td)) : r,
|
||||||
x0 = x - s * r;
|
x0 = x - s * rd;
|
||||||
if (x0 !== x) {
|
if (x0 !== x) {
|
||||||
do {
|
do {
|
||||||
x = x0;
|
evaluate(x0);
|
||||||
// Evaluate q, q', b1 and c2 at x
|
// Newton's. Divide by 1 + MACHINE_EPSILON (1.000...002)
|
||||||
tmp = a * x;
|
// to avoid x0 crossing over a root.
|
||||||
b1 = tmp + b;
|
x0 = qd === 0 ? x : x - q / qd / (1 + MACHINE_EPSILON);
|
||||||
c2 = b1 * x + c;
|
|
||||||
qd = (tmp + b1) * x + c2;
|
|
||||||
q = c2 * x + d;
|
|
||||||
// Newton's. Divide by ec to avoid x0 crossing over a
|
|
||||||
// root.
|
|
||||||
x0 = qd === 0 ? x : x - q / qd / ec;
|
|
||||||
} while (s * x0 > s * x);
|
} while (s * x0 > s * x);
|
||||||
// Adjust the coefficients for the quadratic.
|
// Adjust the coefficients for the quadratic.
|
||||||
if (abs(a) * x * x > abs(d / x)) {
|
if (abs(a) * x * x > abs(d / x)) {
|
||||||
|
|
Loading…
Reference in a new issue