Rubi NumericFactor/NonnumericFactors split of a term: the leading * rational coefficient and the remaining (non-numeric) factors.
(u: Expression)
| 480 | } |
| 481 | |
| 482 | /** Rubi PossibleZeroQ: canonical zero, simplified zero, or numerically ~0 |
| 483 | * |
| 484 | * The `.N()` below must stay UNGATED — do not funnel it through |
| 485 | * `numericValueOf`/`numberLiteralOf` (`boxed-expression/numerics.ts`), whose |
| 486 | * `.unknowns` gate declines anything carrying a free variable. Deciding a |
| 487 | * *symbolic* zero is this predicate's entire job, and `.N()` does it by |
| 488 | * floating the exponents: `(⁴√b/⁴√a)² − √b/√a` numericizes to `0` (both terms |
| 489 | * become `b^0.5·a^-0.5`) where `simplify()` sees nothing. Gating it made this |
| 490 | * return `false` for a true zero and cost the R28a mixed-parity split its |
| 491 | * closed form (integration-rules #544). Same reasoning for `posAux` below. */ |
| 492 | export function zeroQ(d: Expression): boolean { |
| 493 | if (d.isSame(0)) return true; |
| 494 | const key = activeCaches ? d.toString() : ''; |
| 495 | const cached = activeCaches?.zeroQ.get(key); |
| 496 | if (cached !== undefined) return cached; |
| 497 | let result = false; |
| 498 | const s = safeSimplify(d); |
| 499 | if (s.isSame(0)) result = true; |
| 500 | else { |
| 501 | const n = s.N(); |
| 502 | if (isNumber(n) && typeof n.re === 'number' && typeof n.im === 'number') |
| 503 | result = Math.abs(n.re) < 1e-12 && Math.abs(n.im) < 1e-12; |
| 504 | } |
| 505 | activeCaches?.zeroQ.set(key, result); |
| 506 | return result; |
| 507 | } |
| 508 | |
| 509 | function isLiteralInteger(e: Expression): boolean { |
| 510 | return isNumber(e) && e.isInteger === true; |
| 511 | } |
| 512 | function isLiteralRational(e: Expression): boolean { |
| 513 | return isNumber(e) && e.isRational === true; |
| 514 | } |
| 515 |
no test coverage detected