* Extract the integer content (GCD of all integer coefficients) from a * polynomial, then recursively factor the primitive part. * Returns null if content is 1 or coefficients are not all integers. * * IMPORTANT: Does not call .simplify() to avoid infinite recursion.
(expr: Expression, variable: string)
| 481 | for (let i = 1; i * i <= n; i++) { |
| 482 | if (n % i === 0) { |
| 483 | result.push(i); |
| 484 | if (i !== n / i) result.push(n / i); |
| 485 | } |
| 486 | } |
| 487 | return result; |
| 488 | }; |
| 489 | |
| 490 | // Enumerate candidate rational roots ±p/q |
| 491 | const pDivisors = divisors(constantInt); |
| 492 | const qDivisors = divisors(leadingInt); |
| 493 | const candidates: [number, number][] = []; |
| 494 | const seen = new Set<number>(); |
| 495 | for (const p of pDivisors) { |
| 496 | for (const q of qDivisors) { |
| 497 | const pos = p / q; |
| 498 | const neg = -p / q; |
| 499 | if (!seen.has(pos)) { |
| 500 | seen.add(pos); |
| 501 | candidates.push([p, q]); |
| 502 | } |
| 503 | if (!seen.has(neg)) { |
| 504 | seen.add(neg); |
| 505 | candidates.push([-p, q]); |
| 506 | } |
| 507 | } |
| 508 | } |
| 509 | |
| 510 | if (candidates.length > 100) return null; |
| 511 | |
| 512 | const x = ce.symbol(variable); |
| 513 | const factors: Expression[] = []; |
| 514 | let remaining = expr; |
| 515 | |
| 516 | for (const [p, q] of candidates) { |
| 517 | // Check remaining degree |
| 518 | const remDeg = polynomialDegree(remaining, variable); |
| 519 | if (remDeg <= 0) break; |
| 520 | |
| 521 | const root = q === 1 ? ce.number(p) : ce.number(p).div(ce.number(q)); |
| 522 | // Evaluate the remaining polynomial at the candidate root |
| 523 | const value = remaining.subs({ [variable]: root }).N(); |
| 524 | if (!value.isSame(0)) continue; |
| 525 | |
| 526 | // Root found — divide out (x - root) |
| 527 | const linearFactor = |
| 528 | q === 1 ? x.sub(ce.number(p)) : ce.number(q).mul(x).sub(ce.number(p)); |
| 529 | |
| 530 | const divResult = polynomialDivide(remaining, linearFactor, variable); |
| 531 | if (!divResult) continue; |
| 532 | |
| 533 | factors.push(linearFactor); |
| 534 | remaining = divResult[0]; |
| 535 | } |
| 536 | |
| 537 | if (factors.length === 0) return null; |
| 538 | |
| 539 | // Try quadratic factoring on any remaining degree-2 polynomial |
| 540 | const remDeg = polynomialDegree(remaining, variable); |
no test coverage detected