diff --git a/package.json5 b/package.json5 index f83ee88..a0647ae 100644 --- a/package.json5 +++ b/package.json5 @@ -1,8 +1,7 @@ { name: 'pocomath', version: '0.0.0', - description: 'A little proof-of-concept for organizing mathjs by module\ - inclusion, avoiding factory functions.', + description: 'A little proof-of-concept for organizing mathjs by module inclusion, avoiding factory functions.', main: 'index.js', scripts: { 'test:filecase': '!(find . | sort -f | uniq -i -c | grep -v " 1 ")', @@ -24,6 +23,7 @@ mocha: '^10.0.0', }, dependencies: { + 'bigint-isqrt': '^0.2.1', 'typed-function': '^3.0.0', }, } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 22e3de7..4063068 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,10 +1,12 @@ lockfileVersion: 5.4 specifiers: + bigint-isqrt: ^0.2.1 mocha: ^10.0.0 typed-function: ^3.0.0 dependencies: + bigint-isqrt: 0.2.1 typed-function: 3.0.0 devDependencies: @@ -49,6 +51,10 @@ packages: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true + /bigint-isqrt/0.2.1: + resolution: {integrity: sha512-x43s2Qx5l5ShFZFA5xejJfPtV1vXISyWUXlrZeJTx9F6D2ex3BR6AwWnIz4ITAu5nTy3hp+d+ClGu7qUGcgY8g==} + dev: false + /binary-extensions/2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} diff --git a/src/bigint/Types/bigint.mjs b/src/bigint/Types/bigint.mjs index 04bd189..c1416af 100644 --- a/src/bigint/Types/bigint.mjs +++ b/src/bigint/Types/bigint.mjs @@ -1,6 +1,4 @@ -export const Types = { - bigint: { - before: ['Complex'], - test: b => typeof b === 'bigint' - } +export const Type_bigint = { + before: ['Complex'], + test: b => typeof b === 'bigint' } diff --git a/src/bigint/add.mjs b/src/bigint/add.mjs index cc1f48e..31e2926 100644 --- a/src/bigint/add.mjs +++ b/src/bigint/add.mjs @@ -1,4 +1,4 @@ -export {Types} from './Types/bigint.mjs' +export * from './Types/bigint.mjs' export const add = { '...bigint': () => addends => addends.reduce((x,y) => x+y, 0n) diff --git a/src/bigint/all.mjs b/src/bigint/all.mjs index f4cdb60..0f87414 100644 --- a/src/bigint/all.mjs +++ b/src/bigint/all.mjs @@ -1,4 +1,8 @@ -export {Types} from './Types/bigint.mjs' -export {add} from './add.mjs' -export {negate} from './negate.mjs' -export {subtract} from '../generic/subtract.mjs' +export * from './native.mjs' +export * from '../generic/arithmetic.mjs' + +// resolve the conflicts +export {divide} from './divide.mjs' +export {multiply} from './multiply.mjs' +export {sign} from './sign.mjs' +export {sqrt} from './sqrt.mjs' diff --git a/src/bigint/divide.mjs b/src/bigint/divide.mjs new file mode 100644 index 0000000..288230d --- /dev/null +++ b/src/bigint/divide.mjs @@ -0,0 +1,20 @@ +export * from './Types/bigint.mjs' + +export const divide = { + 'bigint,bigint': ({config, 'sign(bigint)': sgn}) => { + if (config.predictable) { + return (n, d) => { + if (sgn(n) === sgn(d)) return n/d + const quot = n/d + if (quot * d == n) return quot + return quot - 1n + } + } else { + return (n, d) => { + const quot = n/d + if (quot * d == n) return quot + return undefined + } + } + } +} diff --git a/src/bigint/multiply.mjs b/src/bigint/multiply.mjs new file mode 100644 index 0000000..7994abc --- /dev/null +++ b/src/bigint/multiply.mjs @@ -0,0 +1,5 @@ +export * from './Types/bigint.mjs' + +export const multiply = { + '...bigint': () => multiplicands => multiplicands.reduce((x,y) => x*y, 1n) +} diff --git a/src/bigint/native.mjs b/src/bigint/native.mjs new file mode 100644 index 0000000..b09076a --- /dev/null +++ b/src/bigint/native.mjs @@ -0,0 +1,9 @@ +export * from './Types/bigint.mjs' +export {add} from './add.mjs' +export {divide} from './divide.mjs' +export {multiply} from './multiply.mjs' +export {negate} from './negate.mjs' +export {one} from './one.mjs' +export {sign} from './sign.mjs' +export {sqrt} from './sqrt.mjs' +export {zero} from './zero.mjs' diff --git a/src/bigint/negate.mjs b/src/bigint/negate.mjs index 874a377..d44cdb0 100644 --- a/src/bigint/negate.mjs +++ b/src/bigint/negate.mjs @@ -1,3 +1,3 @@ -export {Types} from './Types/bigint.mjs' +export * from './Types/bigint.mjs' export const negate = {bigint: () => b => -b} diff --git a/src/bigint/one.mjs b/src/bigint/one.mjs new file mode 100644 index 0000000..f548a65 --- /dev/null +++ b/src/bigint/one.mjs @@ -0,0 +1,3 @@ +export * from './Types/bigint.mjs' + +export const one = {bigint: () => () => 1n} diff --git a/src/bigint/sign.mjs b/src/bigint/sign.mjs new file mode 100644 index 0000000..af48e05 --- /dev/null +++ b/src/bigint/sign.mjs @@ -0,0 +1,9 @@ +export * from './Types/bigint.mjs' + +export const sign = { + bigint: () => b => { + if (b === 0n) return 0n + if (b > 0n) return 1n + return -1n + } +} diff --git a/src/bigint/sqrt.mjs b/src/bigint/sqrt.mjs new file mode 100644 index 0000000..ad6bd67 --- /dev/null +++ b/src/bigint/sqrt.mjs @@ -0,0 +1,30 @@ +export * from './Types/bigint.mjs' +import isqrt from 'bigint-isqrt' + +export const sqrt = { + bigint: ({config, complex, 'self(Complex)': complexSqrt}) => { + 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) { + return b => { + if (b >= 0n) { + const trial = isqrt(b) + if (trial * trial === b) return trial + } + return undefined + } + } + return b => { + if (b >= 0n) { + const trial = isqrt(b) + if (trial * trial === b) return trial + return undefined + } + return complexSqrt(complex(b)) + } + } +} diff --git a/src/bigint/zero.mjs b/src/bigint/zero.mjs new file mode 100644 index 0000000..0c63a1a --- /dev/null +++ b/src/bigint/zero.mjs @@ -0,0 +1,3 @@ +export * from './Types/bigint.mjs' + +export const zero = {bigint: () => () => 0n} diff --git a/src/complex/Types/Complex.mjs b/src/complex/Types/Complex.mjs index f6e3eb2..30bbf3f 100644 --- a/src/complex/Types/Complex.mjs +++ b/src/complex/Types/Complex.mjs @@ -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, so to speak: */ -export function numComplex(z) { - return isComplex(z) && typeof z.re === 'number' && typeof z.im === 'number' -} diff --git a/src/complex/abs.mjs b/src/complex/abs.mjs index 20ab809..63aacd6 100644 --- a/src/complex/abs.mjs +++ b/src/complex/abs.mjs @@ -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))) diff --git a/src/complex/add.mjs b/src/complex/add.mjs index 27374b6..58d9eea 100644 --- a/src/complex/add.mjs +++ b/src/complex/add.mjs @@ -1,4 +1,4 @@ -export {Types} from './Types/Complex.mjs' +export * from './Types/Complex.mjs' export const add = { '...Complex': ({self}) => addends => { diff --git a/src/complex/all.mjs b/src/complex/all.mjs index 2c3946d..ddb7679 100644 --- a/src/complex/all.mjs +++ b/src/complex/all.mjs @@ -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' diff --git a/src/complex/complex.mjs b/src/complex/complex.mjs index 5cbbced..58d3e2e 100644 --- a/src/complex/complex.mjs +++ b/src/complex/complex.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 } diff --git a/src/complex/native.mjs b/src/complex/native.mjs index aec0868..03652ed 100644 --- a/src/complex/native.mjs +++ b/src/complex/native.mjs @@ -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' diff --git a/src/complex/negate.mjs b/src/complex/negate.mjs index 45b9840..7ddaecc 100644 --- a/src/complex/negate.mjs +++ b/src/complex/negate.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)}) diff --git a/src/complex/sqrt.mjs b/src/complex/sqrt.mjs index 93cd10a..cba7361 100644 --- a/src/complex/sqrt.mjs +++ b/src/complex/sqrt.mjs @@ -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)) ) } } diff --git a/src/core/PocomathInstance.mjs b/src/core/PocomathInstance.mjs index 646bd62..7462082 100644 --- a/src/core/PocomathInstance.mjs +++ b/src/core/PocomathInstance.mjs @@ -8,7 +8,8 @@ export default class PocomathInstance { * in that if a new top-level PocomathInstance method is added, its name * must be added to this list. */ - static reserved = new Set(['config', 'importDependencies', 'install', 'name']) + static reserved = new Set([ + 'config', 'importDependencies', 'install', 'name', 'Types']) constructor(name) { this.name = name @@ -65,10 +66,11 @@ export default class PocomathInstance { * operation in the body of the implementation. [NOTE: this signature- * specific reference is not yet implemented.] * - * Note that the "operation" named `Types` is special: it gives - * types that must be installed in the instance. In this case, the keys - * are type names, and the values are plain objects with the following - * properties: + * Note that any "operation" whose name begins with `Type_` is special: + * it defines a types that must be installed in the instance. + * The remainder of the "operation" name following the `_` is the + * name of the type. The value of the "operation" should be a plain + * object with the following properties: * * - test: the predicate for the type * - from: a plain object mapping the names of types that can be converted @@ -78,8 +80,8 @@ export default class PocomathInstance { */ install(ops) { for (const [item, spec] of Object.entries(ops)) { - if (item === 'Types') { - this._installTypes(spec) + if (item.slice(0,5) === 'Type_') { + this._installType(item.slice(5), spec) } else { this._installOp(item, spec) } @@ -128,43 +130,40 @@ export default class PocomathInstance { /* Used internally by install, see the documentation there. * Note that unlike _installOp below, we can do this immediately */ - _installTypes(typeSpecs) { - for (const [type, spec] of Object.entries(typeSpecs)) { - if (type in this.Types) { - if (spec !== this.Types[type]) { - throw new SyntaxError( - `Conflicting definitions of type ${type}`) - } - continue + _installType(type, spec) { + if (type in this.Types) { + if (spec !== this.Types[type]) { + throw new SyntaxError(`Conflicting definitions of type ${type}`) } - let beforeType = 'any' - for (const other of spec.before || []) { - if (other in this.Types) { - beforeType = other - break - } - } - this._typed.addTypes([{name: type, test: spec.test}], beforeType) - /* Now add conversions to this type */ - for (const from in (spec.from || {})) { - if (from in this.Types) { - this._typed.addConversion( - {from, to: type, convert: spec.from[from]}) - } - } - /* And add conversions from this type */ - for (const to in this.Types) { - if (type in (this.Types[to].from || {})) { - this._typed.addConversion( - {from: type, to, convert: this.Types[to].from[type]}) - } - } - this.Types[type] = spec - // rebundle anything that uses the new type: - this._invalidateDependents(':' + type) + return } + let beforeType = 'any' + for (const other of spec.before || []) { + if (other in this.Types) { + beforeType = other + break + } + } + this._typed.addTypes([{name: type, test: spec.test}], beforeType) + /* Now add conversions to this type */ + for (const from in (spec.from || {})) { + if (from in this.Types) { + this._typed.addConversion( + {from, to: type, convert: spec.from[from]}) + } + } + /* And add conversions from this type */ + for (const to in this.Types) { + if (type in (this.Types[to].from || {})) { + this._typed.addConversion( + {from: type, to, convert: this.Types[to].from[type]}) + } + } + this.Types[type] = spec + // rebundle anything that uses the new type: + this._invalidateDependents(':' + type) } - + /* Used internally by install, see the documentation there */ _installOp(name, implementations) { if (name.charAt(0) === '_') { diff --git a/src/generic/Types/generic.mjs b/src/generic/Types/generic.mjs new file mode 100644 index 0000000..473ec56 --- /dev/null +++ b/src/generic/Types/generic.mjs @@ -0,0 +1,2 @@ +export const Type_undefined = {test: u => u === undefined} + diff --git a/src/generic/arithmetic.mjs b/src/generic/arithmetic.mjs index 2787c41..e466b1f 100644 --- a/src/generic/arithmetic.mjs +++ b/src/generic/arithmetic.mjs @@ -1,3 +1,7 @@ +export * from './Types/generic.mjs' + +export {multiply} from './multiply.mjs' export {divide} from './divide.mjs' export {sign} from './sign.mjs' +export {sqrt} from './sqrt.mjs' export {subtract} from './subtract.mjs' diff --git a/src/generic/multiply.mjs b/src/generic/multiply.mjs new file mode 100644 index 0000000..dc078d9 --- /dev/null +++ b/src/generic/multiply.mjs @@ -0,0 +1,12 @@ +export * from './Types/generic.mjs' + +export const multiply = { + 'undefined': () => u => u, + 'undefined,...any': () => (u, rest) => u, + 'any,undefined': () => (x, u) => u, + 'any,undefined,...any': () => (x, u, rest) => u, + 'any,any,undefined': () => (x, y, u) => u, + 'any,any,undefined,...any': () => (x, y, u, rest) => u + // Bit of a hack since this should go on indefinitely... +} + diff --git a/src/generic/sqrt.mjs b/src/generic/sqrt.mjs new file mode 100644 index 0000000..21aa1d5 --- /dev/null +++ b/src/generic/sqrt.mjs @@ -0,0 +1,3 @@ +export * from './Types/generic.mjs' + +export const sqrt = {undefined: () => () => undefined} diff --git a/src/number/Types/number.mjs b/src/number/Types/number.mjs index 417d6f6..f8179fc 100644 --- a/src/number/Types/number.mjs +++ b/src/number/Types/number.mjs @@ -1,8 +1,6 @@ -export const Types = { - number: { - before: ['Complex'], - test: n => typeof n === 'number', - from: {string: s => +s} - } +export const Type_number = { + before: ['Complex'], + test: n => typeof n === 'number', + from: {string: s => +s} } diff --git a/src/number/abs.mjs b/src/number/abs.mjs index 1613356..66ede16 100644 --- a/src/number/abs.mjs +++ b/src/number/abs.mjs @@ -1,3 +1,3 @@ -export {Types} from './Types/number.mjs' +export * from './Types/number.mjs' export const abs = {number: () => n => Math.abs(n)} diff --git a/src/number/add.mjs b/src/number/add.mjs index e473c50..e6610ee 100644 --- a/src/number/add.mjs +++ b/src/number/add.mjs @@ -1,4 +1,4 @@ -export {Types} from './Types/number.mjs' +export * from './Types/number.mjs' export const add = { '...number': () => addends => addends.reduce((x,y) => x+y, 0), diff --git a/src/number/all.mjs b/src/number/all.mjs index e437adb..ef8823e 100644 --- a/src/number/all.mjs +++ b/src/number/all.mjs @@ -1,4 +1,6 @@ -export {Types} from './Types/number.mjs' - -export * from './native.mjs' export * from '../generic/arithmetic.mjs' +export * from './native.mjs' + +// resolve the conflicts +export {sqrt} from './sqrt.mjs' +export {multiply} from './multiply.mjs' diff --git a/src/number/invert.mjs b/src/number/invert.mjs index 11d24c3..4eabe2f 100644 --- a/src/number/invert.mjs +++ b/src/number/invert.mjs @@ -1,3 +1,3 @@ -export {Types} from './Types/number.mjs' +export * from './Types/number.mjs' export const invert = {number: () => n => 1/n} diff --git a/src/number/multiply.mjs b/src/number/multiply.mjs index dff6611..8d7f797 100644 --- a/src/number/multiply.mjs +++ b/src/number/multiply.mjs @@ -1,4 +1,4 @@ -export {Types} from './Types/number.mjs' +export * from './Types/number.mjs' export const multiply = { '...number': () => multiplicands => multiplicands.reduce((x,y) => x*y, 1), diff --git a/src/number/native.js b/src/number/native.js deleted file mode 100644 index 208d8a2..0000000 --- a/src/number/native.js +++ /dev/null @@ -1,4 +0,0 @@ -export {Types} from './Types/number.mjs' -export {add} from './add.mjs' -export {negate} from './negate.mjs' -export {sqrt} from './sqrt.mjs' diff --git a/src/number/native.mjs b/src/number/native.mjs index 99807de..1053579 100644 --- a/src/number/native.mjs +++ b/src/number/native.mjs @@ -1,8 +1,10 @@ -export {Types} from './Types/number.mjs' +export * from './Types/number.mjs' export {abs} from './abs.mjs' export {add} from './add.mjs' export {invert} from './invert.mjs' export {multiply} from './multiply.mjs' export {negate} from './negate.mjs' +export {one} from './one.mjs' export {sqrt} from './sqrt.mjs' +export {zero} from './zero.mjs' diff --git a/src/number/negate.mjs b/src/number/negate.mjs index 387d905..82e27d0 100644 --- a/src/number/negate.mjs +++ b/src/number/negate.mjs @@ -1,3 +1,3 @@ -export { Types } from './Types/number.mjs' +export * from './Types/number.mjs' export const negate = {number: () => n => -n} diff --git a/src/number/one.mjs b/src/number/one.mjs new file mode 100644 index 0000000..5726468 --- /dev/null +++ b/src/number/one.mjs @@ -0,0 +1,3 @@ +export * from './Types/number.mjs' + +export const one = {number: () => () => 1} diff --git a/src/number/sqrt.mjs b/src/number/sqrt.mjs index 179aa0a..f6cc459 100644 --- a/src/number/sqrt.mjs +++ b/src/number/sqrt.mjs @@ -1,4 +1,4 @@ -export { Types } from './Types/number.mjs' +export * from './Types/number.mjs' export const sqrt = { number: ({config, complex, 'self(Complex)': complexSqrt}) => { diff --git a/src/number/zero.mjs b/src/number/zero.mjs new file mode 100644 index 0000000..40ac2fb --- /dev/null +++ b/src/number/zero.mjs @@ -0,0 +1,3 @@ +export * from './Types/number.mjs' + +export const zero = {number: () => () => 0} diff --git a/src/pocomath.mjs b/src/pocomath.mjs index e0015a9..6b61f4f 100644 --- a/src/pocomath.mjs +++ b/src/pocomath.mjs @@ -1,7 +1,7 @@ /* Core of pocomath: generates the default instance */ import PocomathInstance from './core/PocomathInstance.mjs' import * as numbers from './number/native.mjs' -import * as bigints from './bigint/all.mjs' +import * as bigints from './bigint/native.mjs' import * as complex from './complex/native.mjs' import * as generic from './generic/all.mjs' diff --git a/test/_pocomath.mjs b/test/_pocomath.mjs index 7f130dc..e7b30e0 100644 --- a/test/_pocomath.mjs +++ b/test/_pocomath.mjs @@ -22,11 +22,9 @@ describe('The default full pocomath instance "math"', () => { add: { '...stringK': () => addends => addends.reduce((x,y) => x+y, '') }, - Types: { - stringK: { - test: s => typeof s === 'string' && s.charAt(0) === 'K', - before: ['string'] - } + Type_stringK: { + test: s => typeof s === 'string' && s.charAt(0) === 'K', + before: ['string'] } }) assert.strictEqual(math.add('Kilroy','K is here'), 'KilroyK is here') diff --git a/test/bigint/_all.mjs b/test/bigint/_all.mjs new file mode 100644 index 0000000..9c80df3 --- /dev/null +++ b/test/bigint/_all.mjs @@ -0,0 +1,55 @@ +import assert from 'assert' +import math from '../../src/pocomath.mjs' +import PocomathInstance from '../../src/core/PocomathInstance.mjs' +import * as bigintSqrt from '../../src/bigint/sqrt.mjs' +import * as complex from '../../src/complex/all.mjs' +import * as bigints from '../../src/bigint/all.mjs' + +describe('bigint', () => { + it('can divide', () => { + assert.strictEqual(math.divide(15n, 5n), 3n) + assert.strictEqual(math.divide(14n, 5n), undefined) + math.config.predictable = true + assert.strictEqual(math.divide(14n, 5n), 2n) + assert.strictEqual(math.divide(-14n, 5n), -3n) + assert.strictEqual(math.divide(14n, -5n), -3n) + assert.strictEqual(math.divide(-14n, -5n), 2n) + math.config.predictable = false + }) + + it('supports sqrt', () => { + assert.strictEqual(math.sqrt(0n), 0n) + assert.strictEqual(math.sqrt(4n), 2n) + assert.strictEqual(math.sqrt(5n), undefined) + assert.strictEqual( + math.sqrt(82120471531550314555681345949499512621827274120673745141541602816614526075010755373654280259022317599142038423759320355177481886719814621305828811322920076213800348341464996337890625n), + 9062034624274524065844376014975805577107171799890766992670739972241112960081909332275390625n) + assert.deepStrictEqual(math.sqrt(-9n), math.complex(0n, 3n)) + assert.deepStrictEqual( + math.sqrt(math.complex(5n, 12n)), + math.complex(3n, 2n)) + assert.deepStrictEqual(math.sqrt(math.complex(1n, 0n)), 1n) + assert.deepStrictEqual(math.sqrt(math.complex(0n, 1n)), undefined) + math.config.predictable = true + assert.strictEqual(math.sqrt(-9n), -9n) + assert.deepStrictEqual( + math.sqrt(math.complex(1n, 0n)), math.complex(1n, 0n)) + assert.deepStrictEqual( + math.sqrt(math.complex(0n, 1n)), math.complex(0n, 0n)) + assert.deepStrictEqual( + math.sqrt(math.complex(0n, 2n)), math.complex(1n, 1n)) + math.config.predictable = false + assert.deepStrictEqual(math.sqrt(-1024n), math.complex(0n, 32n)) + }) + + it('supports sqrt by itself', () => { + const bo = new PocomathInstance('BigInts Only') + bo.install(bigintSqrt) + assert.strictEqual(bo.sqrt(256n), 16n) + assert.strictEqual(bo.sqrt(-17n), undefined) + bo.install(complex) + bo.install(bigints) + assert.deepStrictEqual(bo.sqrt(-3249n), bo.complex(0n, 57n)) + }) + +}) diff --git a/test/complex/_all.mjs b/test/complex/_all.mjs index 9d09222..1d49855 100644 --- a/test/complex/_all.mjs +++ b/test/complex/_all.mjs @@ -9,6 +9,9 @@ describe('complex', () => { assert.deepStrictEqual( math.sqrt(math.complex(0,1)), math.complex(math.sqrt(0.5), math.sqrt(0.5))) + assert.deepStrictEqual( + math.sqrt(math.complex(5, 12)), + math.complex(3, 2)) math.config.predictable = true assert.deepStrictEqual(math.sqrt(math.complex(1,0)), math.complex(1,0)) assert.deepStrictEqual( diff --git a/test/custom.mjs b/test/custom.mjs index 4df9d67..e057dbf 100644 --- a/test/custom.mjs +++ b/test/custom.mjs @@ -23,7 +23,7 @@ describe('A custom instance', () => { it("can be assembled in any order", () => { bw.install(numbers) - bw.install({Types: {string: {test: s => typeof s === 'string'}}}) + bw.install({Type_string: {test: s => typeof s === 'string'}}) assert.strictEqual(bw.subtract(16, bw.add(3,4,2)), 7) assert.strictEqual(bw.negate('8'), -8) assert.deepStrictEqual(bw.add(bw.complex(1,3), 1), {re: 2, im: 3}) diff --git a/test/number/_all.mjs b/test/number/_all.mjs index b334fef..1af4ed4 100644 --- a/test/number/_all.mjs +++ b/test/number/_all.mjs @@ -4,6 +4,7 @@ import PocomathInstance from '../../src/core/PocomathInstance.mjs' import * as numberSqrt from '../../src/number/sqrt.mjs' import * as complex from '../../src/complex/all.mjs' import * as numbers from '../../src/number/all.mjs' + describe('number', () => { it('supports sqrt', () => { assert.strictEqual(math.sqrt(4), 2)