130 lines
4.0 KiB
TypeScript
130 lines
4.0 KiB
TypeScript
import {Complex, complex_binary, FnComplexUnary} from './type.js'
|
|
import type {
|
|
FnAbsSquare,
|
|
FnAdd,
|
|
FnAddReal,
|
|
FnConj, FnConservativeSqrt, FnDivide,
|
|
FnDivideByReal, FnIsReal, FnIsSquare,
|
|
FnMultiply, FnNaN, FnRe, FnReciprocal, FnSqrt,
|
|
FnSubtract,
|
|
FnUnaryMinus, FnZero
|
|
} from '../interfaces/arithmetic'
|
|
|
|
export const add =
|
|
<T>(dep: {
|
|
add: FnAdd<T>
|
|
}): FnAdd<Complex<T>> =>
|
|
(w, z) => complex_binary(dep.add(w.re, z.re), dep.add(w.im, z.im))
|
|
|
|
export const addReal =
|
|
<T>(dep: {
|
|
addReal: FnAddReal<T, T>
|
|
}): FnAddReal<Complex<T>, T> =>
|
|
(z, r) => complex_binary(dep.addReal(z.re, r), z.im)
|
|
|
|
export const unaryMinus =
|
|
<T>(dep: {
|
|
unaryMinus: FnUnaryMinus<T>
|
|
}): FnUnaryMinus<Complex<T>> =>
|
|
(z) => complex_binary(dep.unaryMinus(z.re), dep.unaryMinus(z.im))
|
|
|
|
export const conj =
|
|
<T>(dep: {
|
|
unaryMinus: FnUnaryMinus<T>,
|
|
conj: FnConj<T>
|
|
}) : FnConj<Complex<T>> =>
|
|
(z) => complex_binary(dep.conj(z.re), dep.unaryMinus(z.im))
|
|
|
|
export const subtract =
|
|
<T>(dep: {
|
|
subtract: FnSubtract<T>
|
|
}): FnSubtract<Complex<T>> =>
|
|
(w, z) => complex_binary(dep.subtract(w.re, z.re), dep.subtract(w.im, z.im))
|
|
|
|
export const multiply =
|
|
<T>(dep: {
|
|
add: FnAdd<T>,
|
|
subtract: FnSubtract<T>,
|
|
multiply: FnMultiply<T>,
|
|
conj: FnConj<T>
|
|
}) =>
|
|
(w, z) => {
|
|
const mult = dep.multiply
|
|
const realpart = dep.subtract(mult(w.re, z.re), mult(dep.conj(w.im), z.im))
|
|
const imagpart = dep.add(mult(dep.conj(w.re), z.im), mult(w.im, z.re))
|
|
return complex_binary(realpart, imagpart)
|
|
}
|
|
|
|
export const absquare =
|
|
<T>(dep: {
|
|
add: FnAdd<T>,
|
|
absquare: FnAbsSquare<T, T>
|
|
}): FnAbsSquare<Complex<T>, T> =>
|
|
(z) => dep.add(dep.absquare(z.re), dep.absquare(z.im))
|
|
|
|
export const divideByReal =
|
|
<T>(dep: {
|
|
divideByReal: FnDivideByReal<T, T>
|
|
}): FnDivideByReal<Complex<T>, T> =>
|
|
(z, r) => complex_binary(dep.divideByReal(z.re, r), dep.divideByReal(z.im, r))
|
|
|
|
export const reciprocal =
|
|
<T>(dep: {
|
|
conj: FnConj<Complex<T>>,
|
|
absquare: FnAbsSquare<Complex<T>, T>,
|
|
divideByReal: FnDivideByReal<Complex<T>, T>
|
|
}): FnReciprocal<Complex<T>> =>
|
|
(z) => dep.divideByReal(dep.conj(z), dep.absquare(z))
|
|
|
|
export const divide =
|
|
<T>(dep: {
|
|
multiply: FnMultiply<Complex<T>>,
|
|
reciprocal: FnReciprocal<Complex<T>>,
|
|
}): FnDivide<Complex<T>> =>
|
|
(w, z) => dep.multiply(w, dep.reciprocal(z))
|
|
|
|
export const complexSqrt =
|
|
<T>(dep: {
|
|
conservativeSqrt: FnConservativeSqrt<T>,
|
|
isSquare: FnIsSquare<T>,
|
|
complex: FnComplexUnary<T>,
|
|
unaryMinus: FnUnaryMinus<T>,
|
|
zero: FnZero<T>,
|
|
nan: FnNaN<Complex<T>>
|
|
}) =>
|
|
(r) => {
|
|
if (dep.isSquare(r)) return dep.complex(dep.conservativeSqrt(r))
|
|
const negative = dep.unaryMinus(r)
|
|
if (dep.isSquare(negative)) {
|
|
return complex_binary(
|
|
dep.zero(r), dep.conservativeSqrt(negative))
|
|
}
|
|
// neither the real number or its negative is a square; could happen
|
|
// for example with bigint. So there is no square root. So we have to
|
|
// return the NaN of the type.
|
|
return dep.nan(dep.complex(r))
|
|
}
|
|
|
|
export const sqrt =
|
|
<T>(dep: {
|
|
isReal: FnIsReal<Complex<T>>,
|
|
complexSqrt: FnSqrt<T>,
|
|
conservativeSqrt: FnConservativeSqrt<T>,
|
|
absquare: FnAbsSquare<Complex<T>, T>,
|
|
addReal: FnAddReal<Complex<T>, T>,
|
|
divideByReal: FnDivideByReal<Complex<T>, T>,
|
|
add: FnAdd<T>,
|
|
re: FnRe<Complex<T>, T>,
|
|
}) =>
|
|
(z: Complex<T>): Complex<T> | T => {
|
|
if (dep.isReal(z)) return dep.complexSqrt(z.re)
|
|
const myabs = dep.conservativeSqrt(dep.absquare(z))
|
|
const num = dep.addReal(z, myabs)
|
|
const r = dep.re(z)
|
|
const denomsq = dep.add(dep.add(myabs, myabs), dep.add(r, r))
|
|
const denom = dep.conservativeSqrt(denomsq)
|
|
return dep.divideByReal(num, denom)
|
|
}
|
|
|
|
export const conservativeSqrt = sqrt
|