fix(Types): Move distinct types into distinct identifiers
This allows types to be collected; prior to this commit they were conflicting from different modules. Uses this fix to extend sqrt to bigint, with the convention that it is undefined for non-perfect squares when 'predictable' is false and is the "best" approximation to the square root when 'predictable' is true. Furthermore, for negative bigints, you might get a Gaussian integer when predictable is false; or you will just get your argument back when 'predictable' is true because what other bigint could you give back for a negative bigint? Also had to modify tests on the sign in sqrt(Complex) and add functions 'zero' and 'one' to get types to match, as expected in #27. Adds numerous tests. Resolves #26. Resolves #27.
This commit is contained in:
parent
b21d2b59fa
commit
f68c7bd1fb
44 changed files with 287 additions and 109 deletions
|
@ -2,21 +2,15 @@
|
|||
* can be any type (for this proof-of-concept; in reality we'd want to
|
||||
* insist on some numeric or scalar supertype).
|
||||
*/
|
||||
export function isComplex(z) {
|
||||
function isComplex(z) {
|
||||
return z && typeof z === 'object' && 're' in z && 'im' in z
|
||||
}
|
||||
|
||||
export const Types = {
|
||||
Complex: {
|
||||
test: isComplex,
|
||||
from: {
|
||||
number: x => ({re: x, im: 0}),
|
||||
bigint: x => ({re: x, im: 0n})
|
||||
}
|
||||
export const Type_Complex = {
|
||||
test: isComplex,
|
||||
from: {
|
||||
number: x => ({re: x, im: 0}),
|
||||
bigint: x => ({re: x, im: 0n})
|
||||
}
|
||||
}
|
||||
|
||||
/* test if an entity is Complex<number>, so to speak: */
|
||||
export function numComplex(z) {
|
||||
return isComplex(z) && typeof z.re === 'number' && typeof z.im === 'number'
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export {Types} from './Types/Complex.mjs'
|
||||
export * from './Types/Complex.mjs'
|
||||
|
||||
export const abs = {Complex: ({sqrt, add, multiply}) => z => {
|
||||
return sqrt(add(multiply(z.re, z.re), multiply(z.im, z.im)))
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export {Types} from './Types/Complex.mjs'
|
||||
export * from './Types/Complex.mjs'
|
||||
|
||||
export const add = {
|
||||
'...Complex': ({self}) => addends => {
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
export * from './native.mjs'
|
||||
export * from '../generic/arithmetic.mjs'
|
||||
export * from './native.mjs'
|
||||
|
||||
// resolve the conflicts
|
||||
export {sqrt} from './sqrt.mjs'
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
export {Types} from './Types/Complex.mjs'
|
||||
export * from './Types/Complex.mjs'
|
||||
export * from '../generic/Types/generic.mjs'
|
||||
|
||||
export const complex = {
|
||||
/* Very permissive for sake of proof-of-concept; would be better to
|
||||
* have a numeric/scalar type, e.g. by implementing subtypes in
|
||||
* typed-function
|
||||
*/
|
||||
'any, any': () => (x, y) => ({re: x, im: y}),
|
||||
'undefined': () => u => u,
|
||||
'undefined,any': () => (u, y) => u,
|
||||
'any,undefined': () => (x, u) => u,
|
||||
'any,any': () => (x, y) => ({re: x, im: y}),
|
||||
/* Take advantage of conversions in typed-function */
|
||||
Complex: () => z => z
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export {Types} from './Types/Complex.mjs'
|
||||
export * from './Types/Complex.mjs'
|
||||
|
||||
export {abs} from './abs.mjs'
|
||||
export {add} from './add.mjs'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export {Types} from './Types/Complex.mjs'
|
||||
export * from './Types/Complex.mjs'
|
||||
|
||||
export const negate = {
|
||||
Complex: ({self}) => z => ({re: self(z.re), im: self(z.im)})
|
||||
|
|
|
@ -1,35 +1,44 @@
|
|||
export { Types } from './Types/Complex.mjs'
|
||||
export * from './Types/Complex.mjs'
|
||||
|
||||
export const sqrt = {
|
||||
Complex: ({
|
||||
config,
|
||||
zero,
|
||||
sign,
|
||||
one,
|
||||
add,
|
||||
complex,
|
||||
multiply,
|
||||
sign,
|
||||
self,
|
||||
divide,
|
||||
add,
|
||||
'abs(Complex)': abs,
|
||||
subtract
|
||||
}) => {
|
||||
if (config.predictable) {
|
||||
return z => {
|
||||
const imZero = zero(z.im)
|
||||
const imSign = sign(z.im)
|
||||
const reOne = one(z.re)
|
||||
const reSign = sign(z.re)
|
||||
if (imSign === 0 && reSign === 1) return complex(self(z.re))
|
||||
if (imSign === imZero && reSign === reOne) return complex(self(z.re))
|
||||
const reTwo = add(reOne, reOne)
|
||||
return complex(
|
||||
multiply(sign(z.im), self(divide(add(abs(z),z.re), 2))),
|
||||
self(divide(subtract(abs(z),z.re), 2))
|
||||
multiply(sign(z.im), self(divide(add(abs(z),z.re), reTwo))),
|
||||
self(divide(subtract(abs(z),z.re), reTwo))
|
||||
)
|
||||
}
|
||||
}
|
||||
return z => {
|
||||
const imZero = zero(z.im)
|
||||
const imSign = sign(z.im)
|
||||
const reOne = one(z.re)
|
||||
const reSign = sign(z.re)
|
||||
if (imSign === 0 && reSign === 1) return self(z.re)
|
||||
if (imSign === imZero && reSign === reOne) return self(z.re)
|
||||
const reTwo = add(reOne, reOne)
|
||||
const partial = add(abs(z), z.re)
|
||||
return complex(
|
||||
multiply(sign(z.im), self(divide(add(abs(z),z.re), 2))),
|
||||
self(divide(subtract(abs(z),z.re), 2))
|
||||
multiply(sign(z.im), self(divide(add(abs(z),z.re), reTwo))),
|
||||
self(divide(subtract(abs(z),z.re), reTwo))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue