| 249 | if (a === 0) return b; |
| 250 | if (b === 0) return a; |
| 251 | // Exact integer path: preserves large-integer correctness, no tolerance. |
| 252 | if (Number.isInteger(a) && Number.isInteger(b)) { |
| 253 | while (b !== 0) [a, b] = [b, a % b]; |
| 254 | return a; |
| 255 | } |
| 256 | // Tolerant floating Euclidean algorithm for non-integer reals. |
| 257 | const mn = Math.min(a, b); |
| 258 | const tol = eps * Math.max(a, b); |
| 259 | // Bounded loop: Euclid converges fast; the cap guards against a pathological |
| 260 | // float residue that never dips below `tol`. |
| 261 | for (let i = 0; i < 10000 && b > tol; i++) [a, b] = [b, a % b]; |
| 262 | // Scale-mismatch guard: when the operands differ in magnitude by more than |
| 263 | // 1/ε, the smaller starts below `tol` and Euclid terminates holding the |
| 264 | // LARGER operand — which would violate gcd ≤ min(|a|,|b|). Return the smaller |
| 265 | // operand instead (it divides the larger to within tolerance). |
| 266 | return a > mn ? mn : a; |
| 267 | } |
| 268 | |
| 269 | /** |
| 270 | * LCM extended to non-integer reals, consistent with {@linkcode realGcd}: |