typocomath/src/numbers/arithmetic.ts

73 lines
3.3 KiB
TypeScript

import {configDependency} from '../core/Config.js'
import {
Signature, ConservativeBinary, ConservativeUnary, Dependency, ImpType
} from '../core/Dispatcher.js'
import type {Complex, UnderlyingReal} from '../Complex/type.js'
declare module "./type" {
interface NumbersReturn<Params> {
// This description loses information: some subtypes like NumInt or
// Positive are closed under addition, but this says that the result
// of add is just a number, not still of the reduced type
// add: Signature<Params, [number, number], number>
// Whereas this one preserves information, but lies
// because it claims all subtypes of number are closed under addition,
// which is not true for `1 | 2 | 3`, for example. But because in
// generics that use add we often need to assign the result of add
// to something of the exact generic type, generics using add won't
// compile unless we lie in this way and assert that add returns
// the subtype.
add: ConservativeBinary<Params, number>
// Not sure how this will need to go when we introduce NumInt.
addReal: Params extends [infer R, infer S]
? R extends number ? S extends R ? R : never : never
: never
unaryMinus: ConservativeUnary<Params, number>
conj: ConservativeUnary<Params, number>
subtract: ConservativeBinary<Params, number>
multiply: ConservativeBinary<Params, number>
absquare: Params extends [infer R]
? R extends number ? UnderlyingReal<R> : never
: never
reciprocal: ConservativeUnary<Params, number>
divide: ConservativeBinary<Params, number>
divideByReal: Params extends [infer R, infer S]
? R extends number ? S extends R ? R : never : never
: never
// best square root that remains the same type
conservativeSqrt: ConservativeUnary<Params, number>
// Best we can do for sqrt at compile time, since actual return
// type depends on config. Not sure how this will play out
// when we make a number-only bundle, but at least the import type
// above for Complex<> does not lead to any emitted JavaScript.
sqrt: Signature<Params, [number], number | Complex<number>>
}
}
export const add: ImpType<'add', [number, number]> = (a, b) => a + b
export const addReal = add
export const unaryMinus: ImpType<'unaryMinus', [number]> = a => -a
export const conj: ImpType<'conj', [number]> = a => a
export const subtract: ImpType<'subtract', [number, number]> = (a, b) => a - b
export const multiply: ImpType<'multiply', [number, number]> = (a, b) => a * b
export const absquare: ImpType<'absquare', [number]> = a => a*a
export const reciprocal: ImpType<'reciprocal', [number]> = a => 1/a
export const divide: ImpType<'divide', [number, number]> = (a, b) => a / b
export const divideByReal: ImpType<'divideByReal', [number, number]> = divide
export const conservativeSqrt: ImpType<'conservativeSqrt', [number]> =
a => isNaN(a) ? NaN : Math.sqrt(a)
export const sqrt =
(dep: configDependency
& Dependency<'complex', [number, number]>): ImpType<'sqrt', [number]> => {
if (dep.config.predictable || !dep.complex) return conservativeSqrt
return a => {
if (isNaN(a)) return NaN
if (a >= 0) return Math.sqrt(a)
return dep.complex(0, Math.sqrt(unaryMinus(a)))
}
}