From 32bc9ca5158720c68c47b0c67281887bffa7973b Mon Sep 17 00:00:00 2001 From: Glen Whitney Date: Fri, 25 Mar 2022 01:54:20 -0700 Subject: [PATCH] feat: Add complex numbers With just the operations we have for numbers, and overall tests. --- complex/add.js | 16 ++++++++++++++++ complex/all.js | 12 ++++++++++++ complex/complex.js | 21 +++++++++++++++++++++ complex/negate.js | 6 ++++++ number/number.js | 16 ++++++++++------ picomath.js | 4 +++- picomathInstance.js | 4 ++++ test/_picomath.js | 8 ++++++++ 8 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 complex/add.js create mode 100644 complex/all.js create mode 100644 complex/complex.js create mode 100644 complex/negate.js diff --git a/complex/add.js b/complex/add.js new file mode 100644 index 0000000..1293a14 --- /dev/null +++ b/complex/add.js @@ -0,0 +1,16 @@ +import { anyComplex } from './complex.js' + +export default function create(pmath) { + const complex = pmath('complex') + return pmath('add', [anyComplex, // naive, but this is just a P-o-C + (...addends) => { + let sum = complex(addends[0]) + for (let i = 1; i < addends.length; ++i) { + const addend = complex(addends[i]) + sum.re += addend.re + sum.im += addend.im + } + return sum + }]) +} + diff --git a/complex/all.js b/complex/all.js new file mode 100644 index 0000000..76e5190 --- /dev/null +++ b/complex/all.js @@ -0,0 +1,12 @@ +import createComplex from './complex.js' +import createAdd from './add.js' +import createNegate from './negate.js' +import createSubtract from '../generic/subtract.js' + +export default function create(pmath) { + createComplex(pmath) + createAdd(pmath) + createNegate(pmath) + createSubtract(pmath) + // not sure if there's anything reasonable to return here +} diff --git a/complex/complex.js b/complex/complex.js new file mode 100644 index 0000000..794e689 --- /dev/null +++ b/complex/complex.js @@ -0,0 +1,21 @@ +/* Use a plain object with keys re and im for a complex */ +export function isComplex(z) { + return z && typeof z === 'object' && 're' in z && 'im' in z +} + +export function anyComplex(args) { + for (let i = 0; i < args.length; ++i) { + if (isComplex(args[i])) return true + } + return false +} + +export default function create(pmath) { + const number = pmath('number') + return pmath('complex', [ + [args => args.length == 2, (x,y) => ({re: number(x), im: number(y)})], + [args => args.length == 1 && isComplex(args[0]), z => z], + [args => args.length == 1, x => ({re: number(x), im: 0})] + ]) +} + diff --git a/complex/negate.js b/complex/negate.js new file mode 100644 index 0000000..a03e7de --- /dev/null +++ b/complex/negate.js @@ -0,0 +1,6 @@ +import { isComplex } from './complex.js' + +export default function create(pmath) { + return pmath('negate', [args => args.length == 1 && isComplex(args[0]), + z => ({re: -z.re, im: -z.im})]) +} diff --git a/number/number.js b/number/number.js index 39476d5..b2f1b21 100644 --- a/number/number.js +++ b/number/number.js @@ -1,14 +1,18 @@ +export function isNumber(x) { + return typeof x === 'number' +} + export function allNumbers(args) { - for (let i = 0; i < args.length; ++i) { - if (typeof args[i] !== 'number') return false - } - return true + for (let i = 0; i < args.length; ++i) { + if (!isNumber(args[i])) return false + } + return true } export function oneNumber(args) { - return args.length === 1 && typeof args[0] === 'number' + return args.length === 1 && isNumber(args[0]) } export default function create(pmath) { - return pmath('number', [() => true, x => Number(x)]) + return pmath('number', [() => true, x => Number(x)]) } diff --git a/picomath.js b/picomath.js index 8a10a23..f8e88ad 100644 --- a/picomath.js +++ b/picomath.js @@ -1,8 +1,10 @@ /* Core of picomath: generates an instance */ import picomathInstance from './picomathInstance.js' import createNumbers from './number/all.js' +import createComplex from './complex/all.js' const math = picomathInstance('math') createNumbers(math) - +createComplex(math) + export default math diff --git a/picomathInstance.js b/picomathInstance.js index c4b3420..04afd13 100644 --- a/picomathInstance.js +++ b/picomathInstance.js @@ -2,6 +2,10 @@ import poortf from './poortf.js' export default function picomathInstance (instName) { + /* Since we have to do it all the time, when we call a picomath instance + * as a function, it takes a name and 0 or more implementations add adds + * them to its poortf property named name, returning that property value. + */ function fn (name, imps) { if (name in fn) { fn[name].addImps(imps) diff --git a/test/_picomath.js b/test/_picomath.js index 4005d2b..84ff19b 100644 --- a/test/_picomath.js +++ b/test/_picomath.js @@ -12,4 +12,12 @@ describe('The default full picomath instance "math"', () => { (...addends) => addends.reduce((x,y) => x+y, '')]) assert.strictEqual(math.add('Kilroy',' is here'), 'Kilroy is here') }) + + it('handles complex numbers', () => { + assert.deepStrictEqual(math.complex(2,3), {re: 2, im: 3}) + assert.deepStrictEqual( + math.subtract(16, math.add(3, math.complex(0,4), 2)), + math.complex(11, -4)) + assert.deepStrictEqual(math.negate(math.complex(3, '8')).im, -8) + }) })