refactor(Complex): Now a template type!
This means that the real and imaginary parts of a Complex must now be the same type. This seems like a real benefit: a Complex with a number real part and a bigint imaginary part does not seem sensible. Note that this is now straining typed-function in (at least) the following ways: (1) In this change, it was necessary to remove the logic that the square root of a negative number calls complex square root, which then calls back to the number square root in its algorithm. (This was creating a circular reference in the typed-function which the old implementation of Complex was somehow sidestepping.) (2) typed-function could not follow conversions that would be allowed by uninstantiated templates (e.g. number => Complex<number> if the latter template has not been instantiated) and so the facility for instantiating a template was surfaced (and for example is called explicitly in the demo loader `extendToComplex`. Similarly, this necessitated making the unary signature of the `complex` conversion function explicit, rather than just via implicit conversion to Complex. (3) I find the order of implementations is mattering more in typed-function definitions, implying that typed-function's sorting algorithm is having trouble distinguishing alternatives. But otherwise, the conversion went quite smoothly and I think is a good demo of the power of this approach. And I expect that it will work even more smoothly if some of the underlying facilities (subtypes, template types) are integrated into typed-function.
This commit is contained in:
parent
845a2354c9
commit
1444b9828f
25 changed files with 240 additions and 157 deletions
|
@ -2,14 +2,18 @@ export * from './Types/bigint.mjs'
|
|||
import isqrt from 'bigint-isqrt'
|
||||
|
||||
export const sqrt = {
|
||||
bigint: ({config, complex, 'self(Complex)': complexSqrt}) => {
|
||||
bigint: ({
|
||||
config,
|
||||
'complex(bigint,bigint)': cplx,
|
||||
'negate(bigint)': neg
|
||||
}) => {
|
||||
if (config.predictable) {
|
||||
// Don't just return the constant isqrt here because the object
|
||||
// gets decorated with info that might need to be different
|
||||
// for different PocomathInstancss
|
||||
return b => isqrt(b)
|
||||
}
|
||||
if (!complexSqrt) {
|
||||
if (!cplx) {
|
||||
return b => {
|
||||
if (b >= 0n) {
|
||||
const trial = isqrt(b)
|
||||
|
@ -19,12 +23,16 @@ export const sqrt = {
|
|||
}
|
||||
}
|
||||
return b => {
|
||||
if (b >= 0n) {
|
||||
const trial = isqrt(b)
|
||||
if (trial * trial === b) return trial
|
||||
return undefined
|
||||
if (b === undefined) return undefined
|
||||
let real = true
|
||||
if (b < 0n) {
|
||||
b = neg(b)
|
||||
real = false
|
||||
}
|
||||
return complexSqrt(complex(b))
|
||||
const trial = isqrt(b)
|
||||
if (trial * trial !== b) return undefined
|
||||
if (real) return trial
|
||||
return cplx(0n, trial)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue