( expr1: Expression, expr2: Expression, fn: (x1: number, x2: number) => number | Complex, bigFn?: (x1: BigDecimal, x2: BigDecimal) => BigDecimal | Complex | number, complexFn?: (x1: Complex, x2: number | Complex) => Complex | number )
| 187 | if ( |
| 188 | isNaNResult(result) && |
| 189 | complexFn && |
| 190 | ops.every((op) => Number.isFinite(op.re)) |
| 191 | ) { |
| 192 | // The value may be complex for real arguments |
| 193 | result = complexFn(...ops.map((op) => ce.complex(op.re, 0))); |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | if (result === undefined) return undefined; |
| 198 | if (result instanceof Complex) { |
| 199 | if (Number.isNaN(result.re) || Number.isNaN(result.im)) return undefined; |
| 200 | // Chop kernel roundoff dust at the machine-roundoff scale, NOT |
| 201 | // `ce.tolerance` — whether a component is noise from the complex kernel is |
| 202 | // a property of the arithmetic, not of the user's comparison tolerance. |
| 203 | return ce.number( |
| 204 | ce._numericValue({ |
| 205 | re: chop(result.re, ROUNDOFF_TOLERANCE), |
| 206 | im: chop(result.im, ROUNDOFF_TOLERANCE), |
| 207 | }) |
| 208 | ); |
| 209 | } |
| 210 | if (typeof result === 'number') { |
| 211 | if (Number.isNaN(result)) return undefined; |
| 212 | return boxMachineNumber(ce, result); |
| 213 | } |
| 214 | if (result.isNaN()) return undefined; |
| 215 | return ce.number(result); |
| 216 | } |
| 217 | |
| 218 | export function apply2( |
| 219 | expr1: Expression, |
| 220 | expr2: Expression, |
| 221 | fn: (x1: number, x2: number) => number | Complex, |
| 222 | bigFn?: (x1: BigDecimal, x2: BigDecimal) => BigDecimal | Complex | number, |
| 223 | complexFn?: (x1: Complex, x2: number | Complex) => Complex | number |
| 224 | ): Expression | undefined { |
| 225 | if (!isNumber(expr1) || !isNumber(expr2)) return undefined; |
| 226 | |
| 227 | const ce = expr1.engine; |
| 228 | |
| 229 | let result: number | Complex | BigDecimal | undefined = undefined; |
| 230 | if (expr1.im !== 0 || expr2.im !== 0) { |
| 231 | result = complexFn?.( |
| 232 | ce.complex(expr1.re, expr1.im), |
| 233 | ce.complex(expr2.re, expr2.im) |
| 234 | ); |
| 235 | } |
| 236 | |
| 237 | if (result === undefined && bigFn) { |
| 238 | let bigRe1 = expr1.bignumRe; |
| 239 | let bigRe2 = expr2.bignumRe; |
| 240 | if (bigRe1 !== undefined || bigRe2 !== undefined) { |
| 241 | bigRe1 ??= ce.bignum(expr1.re); |
| 242 | bigRe2 ??= ce.bignum(expr2.re); |
| 243 | result = bigFn(bigRe1, bigRe2); |
| 244 | } |
| 245 | } |
| 246 | if (result === undefined) { |
no test coverage detected