import {plain} from './helpers.js' import {NumberT} from './NumberT.js' import {OneOf, Returns, ReturnTyping, Undefined} from '#core/Type.js' import {match} from '#core/TypePatterns.js' import {Complex} from '#complex/Complex.js' import {ReturnsAs} from '#generic/helpers.js' const {conservative, full} = ReturnTyping export const abs = plain(Math.abs) export const norm = abs export const normsq = plain(a => a*a) export const add = [ plain((a, b) => a + b), match([Undefined, NumberT], Returns(NumberT, () => NaN)), match([NumberT, Undefined], Returns(NumberT, () => NaN)) ] export const divide = plain((a, b) => a / b) const numberCbrt = a => { if (a === 0) return a const negate = a < 0 if (negate) a = -a let result = a if (isFinite(a)) { result = Math.exp(Math.log(result) / 3) result = (a / (result * result) + (2 * result)) / 3 } return negate ? -result : result } const cbrtIm = Math.sqrt(3) / 2 export const cbrt = match(NumberT, (math, _N, strategy) => { if (strategy === full && math.types.Complex && math.types.Vector) { // return vector of all three complex roots, real one first const C = Complex(NumberT) const vec = math.vector.resolve([C, C, C]) const promote = math.complex.resolve([NumberT]) const cplx = math.complex.resolve([NumberT, NumberT]) return ReturnsAs(vec, x => { const realroot = numberCbrt(x) if (!isFinite(realroot)) { const full = cplx(realroot, realroot) return(promote(realroot), full, full) } return vec(promote(realroot), cplx(-realroot / 2, realroot * cbrtIm), cplx(-realroot / 2, -realroot * cbrtIm)) }) } return Returns(NumberT, numberCbrt) }) export const invert = plain(a => 1/a) export const multiply = [ plain((a, b) => a * b), match([Undefined, NumberT], Returns(NumberT, () => NaN)), match([NumberT, Undefined], Returns(NumberT, () => NaN)) ] export const negate = plain(a => -a) export const sqrt = match(NumberT, (math, _N, strategy) => { if (!math.types.Complex || strategy === conservative) { return Returns(NumberT, Math.sqrt) } const cplx = math.complex.resolve([NumberT, NumberT], full) if (strategy === full) { const cnan = math.nan(Complex(NumberT)) return Returns(Complex(NumberT), a => { if (isNaN(a)) return cnan return a >= 0 ? cplx(Math.sqrt(a), 0) : cplx(0, Math.sqrt(-a)) }) } // strategy === free, return "best" type return Returns(OneOf(NumberT, Complex(NumberT)), a => { if (isNaN(a)) return NaN return a >= 0 ? Math.sqrt(a) : cplx(0, Math.sqrt(-a)) }) }) export const subtract = [ plain((a, b) => a - b), match([Undefined, NumberT], Returns(NumberT, () => NaN)), match([NumberT, Undefined], Returns(NumberT, () => NaN)) ] export const quotient = plain((a,b) => Math.floor(a/b))