From 5c0c8242b464f18539b380cc69762a85c439a6ea Mon Sep 17 00:00:00 2001 From: Kryonn Date: Tue, 21 Oct 2025 10:56:52 -0300 Subject: [PATCH 01/12] code: add nand and nor number operations --- src/plain/number/logical.js | 10 ++++++ test/unit-tests/plain/number/logical.test.js | 35 ++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 test/unit-tests/plain/number/logical.test.js diff --git a/src/plain/number/logical.js b/src/plain/number/logical.js index cb3dc7e3a6..d14c75ab9c 100644 --- a/src/plain/number/logical.js +++ b/src/plain/number/logical.js @@ -11,6 +11,11 @@ export function orNumber (x, y) { } orNumber.signature = n2 +export function norNumber (x, y) { + return !(x || y) +} +norNumber.signature = n2 + export function xorNumber (x, y) { return !!x !== !!y } @@ -20,3 +25,8 @@ export function andNumber (x, y) { return !!(x && y) } andNumber.signature = n2 + +export function nandNumber (x, y) { + return !(x && y) +} +nandNumber.signature = n2 diff --git a/test/unit-tests/plain/number/logical.test.js b/test/unit-tests/plain/number/logical.test.js new file mode 100644 index 0000000000..7ade7237c5 --- /dev/null +++ b/test/unit-tests/plain/number/logical.test.js @@ -0,0 +1,35 @@ +import assert from 'assert' +import { nandNumber } from '../../../../src/plain/number/logical.js' +import { norNumber } from '../../../../src/plain/number/logical.js' + +describe('nand', function () { + it('should return true when both are 0', function () { + assert.strictEqual(nandNumber(0, 0), true) + }) + + it('should return true when one is 0 and the other is 1', function () { + assert.strictEqual(nandNumber(1, 0), true) + assert.strictEqual(nandNumber(0, 1), true) + }) + + it('should return false when both are 1', function () { + assert.strictEqual(nandNumber(1, 1), false) + }) + +}) + +describe('nor', function () { + it('should return true when both are 0', function () { + assert.strictEqual(norNumber(0, 0), true) + }) + + it('should return false when one is 0 and the other is 1', function () { + assert.strictEqual(norNumber(1, 0), false) + assert.strictEqual(norNumber(0, 1), false) + }) + + it('should return false when both are 1', function () { + assert.strictEqual(norNumber(1, 1), false) + }) + +}) From 4cfd5be71362bcfd924ef7f49aad7c4a82a4e99d Mon Sep 17 00:00:00 2001 From: Kryonn Date: Mon, 27 Oct 2025 20:10:55 -0300 Subject: [PATCH 02/12] code: update nor --- src/factoriesAny.js | 2 + src/function/logical/nor.js | 75 ++++++ test/unit-tests/function/logical/nor.test.js | 236 +++++++++++++++++++ 3 files changed, 313 insertions(+) create mode 100644 src/function/logical/nor.js create mode 100644 test/unit-tests/function/logical/nor.test.js diff --git a/src/factoriesAny.js b/src/factoriesAny.js index 89b49af029..8dcec42679 100644 --- a/src/factoriesAny.js +++ b/src/factoriesAny.js @@ -70,6 +70,7 @@ export { createRe } from './function/complex/re.js' export { createNot } from './function/logical/not.js' export { createNullish } from './function/logical/nullish.js' export { createOr } from './function/logical/or.js' +export { createNor } from './function/logical/nor.js' export { createXor } from './function/logical/xor.js' export { createConcat } from './function/matrix/concat.js' export { createColumn } from './function/matrix/column.js' @@ -129,6 +130,7 @@ export { createLeftShift } from './function/bitwise/leftShift.js' export { createRightArithShift } from './function/bitwise/rightArithShift.js' export { createRightLogShift } from './function/bitwise/rightLogShift.js' export { createAnd } from './function/logical/and.js' +export { createNand } from './function/logical/nand.js' export { createCompare } from './function/relational/compare.js' export { createCompareNatural } from './function/relational/compareNatural.js' export { createCompareText } from './function/relational/compareText.js' diff --git a/src/function/logical/nor.js b/src/function/logical/nor.js new file mode 100644 index 0000000000..8673768aa0 --- /dev/null +++ b/src/function/logical/nor.js @@ -0,0 +1,75 @@ +import { createMatAlgo03xDSf } from '../../type/matrix/utils/matAlgo03xDSf.js' +import { createMatAlgo12xSfs } from '../../type/matrix/utils/matAlgo12xSfs.js' +import { createMatAlgo05xSfSf } from '../../type/matrix/utils/matAlgo05xSfSf.js' +import { factory } from '../../utils/factory.js' +import { createMatrixAlgorithmSuite } from '../../type/matrix/utils/matrixAlgorithmSuite.js' +import { norNumber } from '../../plain/number/logical.js' + +const name = 'nor' +const dependencies = [ + 'typed', + 'matrix', + 'equalScalar', + 'DenseMatrix', + 'concat' +] + +export const createNor = /* #__PURE__ */ factory(name, dependencies, ({ typed, matrix, equalScalar, DenseMatrix, concat }) => { + const matAlgo03xDSf = createMatAlgo03xDSf({ typed }) + const matAlgo05xSfSf = createMatAlgo05xSfSf({ typed, equalScalar }) + const matAlgo12xSfs = createMatAlgo12xSfs({ typed, DenseMatrix }) + const matrixAlgorithmSuite = createMatrixAlgorithmSuite({ typed, matrix, concat }) + + /** + * Logical `or`. Test if at least one value is defined with a nonzero/nonempty value. + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.or(x, y) + * + * Examples: + * + * math.or(2, 4) // returns true + * + * a = [2, 5, 0] + * b = [0, 22, 0] + * c = 0 + * + * math.or(a, b) // returns [true, true, false] + * math.or(b, c) // returns [false, true, false] + * + * See also: + * + * and, not, xor + * + * @param {number | BigNumber | bigint | Complex | Unit | Array | Matrix} x First value to check + * @param {number | BigNumber | bigint | Complex | Unit | Array | Matrix} y Second value to check + * @return {boolean | Array | Matrix} + * Returns true when one of the inputs is defined with a nonzero/nonempty value. + */ + return typed( + name, + { + 'number, number': norNumber, + + 'Complex, Complex': function (x, y) { + return !((x.re !== 0 || x.im !== 0) || (y.re !== 0 || y.im !== 0)) + }, + + 'BigNumber, BigNumber': function (x, y) { + return !((!x.isZero() && !x.isNaN()) || (!y.isZero() && !y.isNaN())) + }, + + 'bigint, bigint': norNumber, + + 'Unit, Unit': typed.referToSelf(self => + (x, y) => self(x.value || 0, y.value || 0)) + }, + matrixAlgorithmSuite({ + SS: matAlgo05xSfSf, + DS: matAlgo03xDSf, + Ss: matAlgo12xSfs + }) + ) +}) diff --git a/test/unit-tests/function/logical/nor.test.js b/test/unit-tests/function/logical/nor.test.js new file mode 100644 index 0000000000..4256e32d3d --- /dev/null +++ b/test/unit-tests/function/logical/nor.test.js @@ -0,0 +1,236 @@ +// test nor +import assert from 'assert' + +import math from '../../../../src/defaultInstance.js' +const bignumber = math.bignumber +const complex = math.complex +const matrix = math.matrix +const sparse = math.sparse +const unit = math.unit +const nor = math.nor + +describe('nor', function () { + it('should nor two numbers correctly', function () { + assert.strictEqual(nor(1, 1), false) + assert.strictEqual(nor(-1, 1), false) + assert.strictEqual(nor(-1, -1), false) + assert.strictEqual(nor(0, -1), false) + assert.strictEqual(nor(1, 0), false) + assert.strictEqual(nor(1, NaN), false) + assert.strictEqual(nor(NaN, 1), false) + assert.strictEqual(nor(1e10, 0.019209), false) + assert.strictEqual(nor(-1.0e-100, 1.0e-100), false) + assert.strictEqual(nor(Infinity, -Infinity), false) + assert.strictEqual(nor(NaN, NaN), true) + assert.strictEqual(nor(NaN, 0), true) + assert.strictEqual(nor(0, NaN), true) + assert.strictEqual(nor(0, 0), true) + }) + + it('should nor two complex numbers', function () { + assert.strictEqual(nor(complex(1, 1), complex(1, 1)), false) + assert.strictEqual(nor(complex(0, 1), complex(1, 1)), false) + assert.strictEqual(nor(complex(1, 0), complex(1, 1)), false) + assert.strictEqual(nor(complex(1, 1), complex(0, 1)), false) + assert.strictEqual(nor(complex(1, 1), complex(1, 0)), false) + assert.strictEqual(nor(complex(1, 0), complex(1, 0)), false) + assert.strictEqual(nor(complex(0, 1), complex(0, 1)), false) + assert.strictEqual(nor(complex(0, 0), complex(1, 1)), false) + assert.strictEqual(nor(complex(0, 0), complex(0, 1)), false) + assert.strictEqual(nor(complex(0, 0), complex(1, 0)), false) + assert.strictEqual(nor(complex(1, 1), complex(0, 0)), false) + assert.strictEqual(nor(complex(0, 1), complex(0, 0)), false) + assert.strictEqual(nor(complex(1, 0), complex(0, 0)), false) + assert.strictEqual(nor(complex(), complex(1, 1)), false) + assert.strictEqual(nor(complex(0), complex(1, 1)), false) + assert.strictEqual(nor(complex(1), complex(1, 1)), false) + assert.strictEqual(nor(complex(1, 1), complex()), false) + assert.strictEqual(nor(complex(1, 1), complex(0)), false) + assert.strictEqual(nor(complex(1, 1), complex(1)), false) + assert.strictEqual(nor(complex(0, 0), complex(0, 0)), true) + assert.strictEqual(nor(complex(), complex()), true) + }) + + it('should nor mixed numbers and complex numbers', function () { + assert.strictEqual(nor(complex(1, 1), 1), false) + assert.strictEqual(nor(complex(1, 1), 0), false) + assert.strictEqual(nor(1, complex(1, 1)), false) + assert.strictEqual(nor(0, complex(1, 1)), false) + assert.strictEqual(nor(complex(0, 0), 1), false) + assert.strictEqual(nor(1, complex(0, 0)), false) + assert.strictEqual(nor(0, complex(0, 0)), true) + assert.strictEqual(nor(complex(0, 0), 0), true) + }) + + it('should nor two booleans', function () { + assert.strictEqual(nor(true, true), false) + assert.strictEqual(nor(true, false), false) + assert.strictEqual(nor(false, true), false) + assert.strictEqual(nor(false, false), true) + }) + + it('should nor mixed numbers and booleans', function () { + assert.strictEqual(nor(2, true), false) + assert.strictEqual(nor(2, false), false) + assert.strictEqual(nor(0, true), false) + assert.strictEqual(nor(0, false), true) + assert.strictEqual(nor(true, 2), false) + assert.strictEqual(nor(false, 2), false) + assert.strictEqual(nor(false, 0), true) + }) + + it('should nor bignumbers', function () { + assert.strictEqual(nor(bignumber(1), bignumber(1)), false) + assert.strictEqual(nor(bignumber(-1), bignumber(1)), false) + assert.strictEqual(nor(bignumber(-1), bignumber(-1)), false) + assert.strictEqual(nor(bignumber(0), bignumber(-1)), false) + assert.strictEqual(nor(bignumber(1), bignumber(0)), false) + assert.strictEqual(nor(bignumber(1), bignumber(NaN)), false) + assert.strictEqual(nor(bignumber(NaN), bignumber(1)), false) + assert.strictEqual(nor(bignumber('1e+10'), bignumber(0.19209)), false) + assert.strictEqual(nor(bignumber('-1.0e-100'), bignumber('1.0e-100')), false) + assert.strictEqual(nor(bignumber(Infinity), bignumber(-Infinity)), false) + assert.strictEqual(nor(bignumber(NaN), bignumber(NaN)), true) + assert.strictEqual(nor(bignumber(NaN), bignumber(0)), true) + assert.strictEqual(nor(bignumber(0), bignumber(NaN)), true) + assert.strictEqual(nor(bignumber(0), bignumber(0)), true) + }) + + it('should nor bigints', function () { + assert.strictEqual(nor(1n, 1n), false) + assert.strictEqual(nor(-1n, 1n), false) + assert.strictEqual(nor(-1n, -1n), false) + assert.strictEqual(nor(0n, -1n), false) + assert.strictEqual(nor(1n, 0n), false) + }) + + it('should nor mixed numbers and bignumbers', function () { + assert.strictEqual(nor(bignumber(2), 3), false) + assert.strictEqual(nor(2, bignumber(2)), false) + assert.strictEqual(nor(0, bignumber(2)), false) + assert.strictEqual(nor(2, bignumber(0)), false) + assert.strictEqual(nor(bignumber(0), 2), false) + assert.strictEqual(nor(bignumber(0), 0), true) + assert.strictEqual(nor(bignumber(2), 0), false) + assert.strictEqual(nor(bignumber(0), 0), true) + }) + + it('should nor mixed numbers and bigints', function () { + assert.strictEqual(nor(2n, 3), false) + assert.strictEqual(nor(2, 3n), false) + }) + + it('should nor two units', function () { + assert.strictEqual(nor(unit('100cm'), unit('10inch')), false) + assert.strictEqual(nor(unit('100cm'), unit('0 inch')), false) + assert.strictEqual(nor(unit('0cm'), unit('1m')), false) + assert.strictEqual(nor(unit('m'), unit('1m')), false) + assert.strictEqual(nor(unit('1dm'), unit('m')), false) + assert.strictEqual(nor(unit('dm'), unit('m')), true) + assert.strictEqual(nor(unit('-100cm'), unit('-10inch')), false) + assert.strictEqual(nor(unit(5, 'km'), unit(100, 'gram')), false) + assert.strictEqual(nor(unit(5, 'km'), unit(0, 'gram')), false) + assert.strictEqual(nor(unit(0, 'km'), unit(100, 'gram')), false) + assert.strictEqual(nor(unit(0, 'km'), unit(0, 'gram')), true) + + assert.strictEqual(nor(unit(bignumber(0), 'm'), unit(bignumber(0), 'm')), true) + assert.strictEqual(nor(unit(bignumber(1), 'm'), unit(bignumber(0), 'm')), false) + assert.strictEqual(nor(unit(bignumber(0), 'm'), unit(bignumber(1), 'm')), false) + assert.strictEqual(nor(unit(bignumber(1), 'm'), unit(bignumber(1), 'm')), false) + }) + + it('should nor two arrays', function () { + assert.deepStrictEqual(nor([0, 1, 0, 12], [0, 0, 1, 22]), [true, false, false, false]) + assert.deepStrictEqual(nor([], []), []) + }) + + it('should nor mixed numbers and arrays', function () { + assert.deepStrictEqual(nor(10, [0, 2]), [false, false]) + assert.deepStrictEqual(nor([0, 2], 10), [false, false]) + assert.deepStrictEqual(nor(0, [0, 2]), [true, false]) + assert.deepStrictEqual(nor([0, 2], 0), [true, false]) + }) + + describe('Array', function () { + it('should nor array - scalar', function () { + assert.deepStrictEqual(nor(10, [0, 2]), [false, false]) + assert.deepStrictEqual(nor([0, 2], 10), [false, false]) + }) + + it('should nor array - array', function () { + assert.deepStrictEqual(nor([0, 1, 0, 12], [0, 0, 1, 22]), [true, false, false, false]) + assert.deepStrictEqual(nor([], []), []) + }) + + it('should nor broadcastable arrays', function () { + assert.deepStrictEqual(nor([[0, 1, 0, 12]], [[0], [0], [1], [22]]), [[true, false, true, false], [true, false, true, false], [false, false, false, false], [false, false, false, false]]) + }) + + it('should nor array - dense matrix', function () { + assert.deepStrictEqual(nor([0, 1, 0, 12], matrix([0, 0, 1, 22])), matrix([true, false, false, false])) + assert.deepStrictEqual(nor([], matrix([])), matrix([])) + }) + + it('should nor array - sparse matrix', function () { + assert.deepStrictEqual(nor([[0, 1], [0, 12]], sparse([[0, 0], [1, 22]])), matrix([[true, false], [false, false]])) + }) + }) + + describe('DenseMatrix', function () { + it('should nor dense matrix - scalar', function () { + assert.deepStrictEqual(nor(10, matrix([0, 2])), matrix([false, false])) + assert.deepStrictEqual(nor(matrix([0, 2]), 10), matrix([false, false])) + }) + + it('should nor dense matrix - array', function () { + assert.deepStrictEqual(nor(matrix([0, 1, 0, 12]), [0, 0, 1, 22]), matrix([true, false, false, false])) + assert.deepStrictEqual(nor(matrix([]), []), matrix([])) + }) + + it('should nor dense matrix - dense matrix', function () { + assert.deepStrictEqual(nor(matrix([0, 1, 0, 12]), matrix([0, 0, 1, 22])), matrix([true, false, false, false])) + assert.deepStrictEqual(nor(matrix([]), matrix([])), matrix([])) + }) + + it('should nor dense matrix - sparse matrix', function () { + assert.deepStrictEqual(nor(matrix([[0, 1], [0, 12]]), sparse([[0, 0], [1, 22]])), matrix([[true, false], [false, false]])) + }) + }) + + describe('SparseMatrix', function () { + it('should nor sparse matrix - scalar', function () { + assert.deepStrictEqual(nor(10, sparse([[0], [2]])), matrix([[false], [false]])) + assert.deepStrictEqual(nor(sparse([[0], [2]]), 10), matrix([[false], [false]])) + }) + + it('should nor sparse matrix - array', function () { + assert.deepStrictEqual(nor(sparse([[0, 1], [0, 12]]), [[0, 0], [1, 22]]), matrix([[true, false], [false, false]])) + }) + + it('should nor sparse matrix - dense matrix', function () { + assert.deepStrictEqual(nor(sparse([[0, 1], [0, 12]]), matrix([[0, 0], [1, 22]])), matrix([[true, false], [false, false]])) + }) + + it('should nor sparse matrix - sparse matrix', function () { + assert.deepStrictEqual(nor(sparse([[0, 1], [0, 12]]), sparse([[0, 0], [1, 22]])), sparse([[true, false], [false, false]])) + }) + }) + + it('should throw an error in case of invalid number of arguments', function () { + assert.throws(function () { nor(1) }, /TypeError: Too few arguments/) + assert.throws(function () { nor(1, 2, 3) }, /TypeError: Too many arguments/) + }) + + it('should throw an error in case of invalid type of arguments', function () { + assert.throws(function () { nor(2, null) }, /TypeError: Unexpected type of argument/) + assert.throws(function () { nor(new Date(), false) }, /TypeError: Unexpected type of argument/) + assert.throws(function () { nor(false, new Date()) }, /TypeError: Unexpected type of argument/) + assert.throws(function () { nor(false, undefined) }, /TypeError: Unexpected type of argument/) + assert.throws(function () { nor(undefined, false) }, /TypeError: Unexpected type of argument/) + }) + + it('should LaTeX nor', function () { + const expression = math.parse('nor(1,2)') + assert.strictEqual(expression.toTex(), '\\left(1\\2\\right)') + }) +}) From 946c22b1f4019f04a4b93739a8e453e6177319aa Mon Sep 17 00:00:00 2001 From: Kryonn Date: Mon, 27 Oct 2025 20:48:13 -0300 Subject: [PATCH 03/12] code: final update nor --- src/function/logical/nor.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/function/logical/nor.js b/src/function/logical/nor.js index 8673768aa0..f39ad8217c 100644 --- a/src/function/logical/nor.js +++ b/src/function/logical/nor.js @@ -1,6 +1,6 @@ import { createMatAlgo03xDSf } from '../../type/matrix/utils/matAlgo03xDSf.js' import { createMatAlgo12xSfs } from '../../type/matrix/utils/matAlgo12xSfs.js' -import { createMatAlgo05xSfSf } from '../../type/matrix/utils/matAlgo05xSfSf.js' +import { createMatAlgo07xSSf } from '../../type/matrix/utils/matAlgo07xSSf.js' import { factory } from '../../utils/factory.js' import { createMatrixAlgorithmSuite } from '../../type/matrix/utils/matrixAlgorithmSuite.js' import { norNumber } from '../../plain/number/logical.js' @@ -16,37 +16,37 @@ const dependencies = [ export const createNor = /* #__PURE__ */ factory(name, dependencies, ({ typed, matrix, equalScalar, DenseMatrix, concat }) => { const matAlgo03xDSf = createMatAlgo03xDSf({ typed }) - const matAlgo05xSfSf = createMatAlgo05xSfSf({ typed, equalScalar }) + const matAlgo07xSSf = createMatAlgo07xSSf({ typed, equalScalar }) const matAlgo12xSfs = createMatAlgo12xSfs({ typed, DenseMatrix }) const matrixAlgorithmSuite = createMatrixAlgorithmSuite({ typed, matrix, concat }) /** - * Logical `or`. Test if at least one value is defined with a nonzero/nonempty value. + * Logical `nor`. Test if both os values are defined with zero. * For matrices, the function is evaluated element wise. * * Syntax: * - * math.or(x, y) + * math.nor(x, y) * * Examples: * - * math.or(2, 4) // returns true + * math.nor(2, 4) // returns false * * a = [2, 5, 0] * b = [0, 22, 0] * c = 0 * - * math.or(a, b) // returns [true, true, false] - * math.or(b, c) // returns [false, true, false] + * math.or(a, b) // returns [false, false, true] + * math.or(b, c) // returns [true, false, true] * * See also: * - * and, not, xor + * and,nand, or, not, xor * * @param {number | BigNumber | bigint | Complex | Unit | Array | Matrix} x First value to check * @param {number | BigNumber | bigint | Complex | Unit | Array | Matrix} y Second value to check * @return {boolean | Array | Matrix} - * Returns true when one of the inputs is defined with a nonzero/nonempty value. + * Returns true when both inputs are zero */ return typed( name, @@ -67,7 +67,7 @@ export const createNor = /* #__PURE__ */ factory(name, dependencies, ({ typed, m (x, y) => self(x.value || 0, y.value || 0)) }, matrixAlgorithmSuite({ - SS: matAlgo05xSfSf, + SS: matAlgo07xSSf, DS: matAlgo03xDSf, Ss: matAlgo12xSfs }) From 2db176a9491a7f84e908c62b6fa1abe44ae3e010 Mon Sep 17 00:00:00 2001 From: Kryonn Date: Thu, 30 Oct 2025 10:02:51 -0300 Subject: [PATCH 04/12] code: nor update --- src/expression/embeddedDocs/embeddedDocs.js | 2 ++ .../embeddedDocs/function/logical/nor.js | 17 ++++++++++++ src/factoriesNumber.js | 2 ++ src/function/logical/nor.js | 14 +++++----- test/unit-tests/plain/number/logical.test.js | 18 ------------- types/index.d.ts | 27 +++++++++++++++++++ 6 files changed, 55 insertions(+), 25 deletions(-) create mode 100644 src/expression/embeddedDocs/function/logical/nor.js diff --git a/src/expression/embeddedDocs/embeddedDocs.js b/src/expression/embeddedDocs/embeddedDocs.js index 9c6d124161..7b7cc31168 100644 --- a/src/expression/embeddedDocs/embeddedDocs.js +++ b/src/expression/embeddedDocs/embeddedDocs.js @@ -114,6 +114,7 @@ import { andDocs } from './function/logical/and.js' import { notDocs } from './function/logical/not.js' import { nullishDocs } from './function/logical/nullish.js' import { orDocs } from './function/logical/or.js' +import { norDocs } from './function/logical/nor.js' import { xorDocs } from './function/logical/xor.js' import { mapSlicesDocs } from './function/matrix/mapSlices.js' import { columnDocs } from './function/matrix/column.js' @@ -450,6 +451,7 @@ export const embeddedDocs = { not: notDocs, nullish: nullishDocs, or: orDocs, + nor: norDocs, xor: xorDocs, // functions - matrix diff --git a/src/expression/embeddedDocs/function/logical/nor.js b/src/expression/embeddedDocs/function/logical/nor.js new file mode 100644 index 0000000000..1556e478f0 --- /dev/null +++ b/src/expression/embeddedDocs/function/logical/nor.js @@ -0,0 +1,17 @@ +export const norDocs = { + name: 'nor', + category: 'Logical', + syntax: [ + 'x nor y', + 'nor(x, y)' + ], + description: 'Logical nor. Test if both values are zero', + examples: [ + 'true nor false', + 'false nor false', + '0 nor 4' + ], + seealso: [ + 'not', 'and', 'xor', 'or', 'nand' + ] +} diff --git a/src/factoriesNumber.js b/src/factoriesNumber.js index 0047dc3624..182fed7aa1 100644 --- a/src/factoriesNumber.js +++ b/src/factoriesNumber.js @@ -48,6 +48,7 @@ import { modNumber, multiplyNumber, normNumber, + norNumber, notNumber, nthRootNumber, orNumber, @@ -207,6 +208,7 @@ export const createAnd = /* #__PURE__ */ createNumberFactory('and', andNumber) export const createNot = /* #__PURE__ */ createNumberFactory('not', notNumber) export const createOr = /* #__PURE__ */ createNumberFactory('or', orNumber) export const createXor = /* #__PURE__ */ createNumberFactory('xor', xorNumber) +export const createNor = /* #__PURE__ */ createNumberFactory('nor', norNumber) // matrix export { createMapSlices } from './function/matrix/mapSlices.js' diff --git a/src/function/logical/nor.js b/src/function/logical/nor.js index f39ad8217c..515c98744d 100644 --- a/src/function/logical/nor.js +++ b/src/function/logical/nor.js @@ -1,6 +1,6 @@ import { createMatAlgo03xDSf } from '../../type/matrix/utils/matAlgo03xDSf.js' import { createMatAlgo12xSfs } from '../../type/matrix/utils/matAlgo12xSfs.js' -import { createMatAlgo07xSSf } from '../../type/matrix/utils/matAlgo07xSSf.js' +import { createMatAlgo05xSfSf } from '../../type/matrix/utils/matAlgo05xSfSf.js' import { factory } from '../../utils/factory.js' import { createMatrixAlgorithmSuite } from '../../type/matrix/utils/matrixAlgorithmSuite.js' import { norNumber } from '../../plain/number/logical.js' @@ -16,12 +16,12 @@ const dependencies = [ export const createNor = /* #__PURE__ */ factory(name, dependencies, ({ typed, matrix, equalScalar, DenseMatrix, concat }) => { const matAlgo03xDSf = createMatAlgo03xDSf({ typed }) - const matAlgo07xSSf = createMatAlgo07xSSf({ typed, equalScalar }) + const matAlgo05xSfSf = createMatAlgo05xSfSf({ typed, equalScalar }) const matAlgo12xSfs = createMatAlgo12xSfs({ typed, DenseMatrix }) const matrixAlgorithmSuite = createMatrixAlgorithmSuite({ typed, matrix, concat }) /** - * Logical `nor`. Test if both os values are defined with zero. + * Logical `nor`. Test if both of values are defined with zero. * For matrices, the function is evaluated element wise. * * Syntax: @@ -36,12 +36,12 @@ export const createNor = /* #__PURE__ */ factory(name, dependencies, ({ typed, m * b = [0, 22, 0] * c = 0 * - * math.or(a, b) // returns [false, false, true] - * math.or(b, c) // returns [true, false, true] + * math.nor(a, b) // returns [false, false, true] + * math.nor(b, c) // returns [true, false, true] * * See also: * - * and,nand, or, not, xor + * and, nand, or, not, xor * * @param {number | BigNumber | bigint | Complex | Unit | Array | Matrix} x First value to check * @param {number | BigNumber | bigint | Complex | Unit | Array | Matrix} y Second value to check @@ -67,7 +67,7 @@ export const createNor = /* #__PURE__ */ factory(name, dependencies, ({ typed, m (x, y) => self(x.value || 0, y.value || 0)) }, matrixAlgorithmSuite({ - SS: matAlgo07xSSf, + SS: matAlgo05xSfSf, DS: matAlgo03xDSf, Ss: matAlgo12xSfs }) diff --git a/test/unit-tests/plain/number/logical.test.js b/test/unit-tests/plain/number/logical.test.js index 7ade7237c5..2eedd4ad24 100644 --- a/test/unit-tests/plain/number/logical.test.js +++ b/test/unit-tests/plain/number/logical.test.js @@ -1,23 +1,6 @@ import assert from 'assert' -import { nandNumber } from '../../../../src/plain/number/logical.js' import { norNumber } from '../../../../src/plain/number/logical.js' -describe('nand', function () { - it('should return true when both are 0', function () { - assert.strictEqual(nandNumber(0, 0), true) - }) - - it('should return true when one is 0 and the other is 1', function () { - assert.strictEqual(nandNumber(1, 0), true) - assert.strictEqual(nandNumber(0, 1), true) - }) - - it('should return false when both are 1', function () { - assert.strictEqual(nandNumber(1, 1), false) - }) - -}) - describe('nor', function () { it('should return true when both are 0', function () { assert.strictEqual(norNumber(0, 0), true) @@ -31,5 +14,4 @@ describe('nor', function () { it('should return false when both are 1', function () { assert.strictEqual(norNumber(1, 1), false) }) - }) diff --git a/types/index.d.ts b/types/index.d.ts index 4c4dd60d75..5d14a2aabe 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -359,6 +359,7 @@ export type OperatorNodeMap = { xor: 'xor' and: 'and' or: 'or' + nor: 'nor' bitOr: '|' bitXor: '^|' bitAnd: '&' @@ -1901,6 +1902,18 @@ export interface MathJsInstance extends MathJsFactory { y: number | BigNumber | bigint | Complex | Unit | MathCollection ): boolean | MathCollection + /** + * Logical nor. Test if both of values are zero + * For matrices, the function is evaluated element wise. + * @param x First value to nor + * @param y Second value to nor + * @returns Returns true when both of the inputs are defined with zero. + */ + nor( + x: number | BigNumber | bigint | Complex | Unit | MathCollection, + y: number | BigNumber | bigint | Complex | Unit | MathCollection + ): boolean | MathCollection + /** * Logical xor. Test whether one and only one value is defined with a * nonzero/nonempty value. For matrices, the function is evaluated @@ -4072,6 +4085,7 @@ export const { andDependencies, notDependencies, orDependencies, + norDependencies, xorDependencies, // matrix function dependencies @@ -5990,6 +6004,18 @@ export interface MathJsChain { y: number | BigNumber | bigint | Complex | Unit | MathCollection ): MathJsChain + /** + * Logical nor. Test if both of value are defined with zero. + * For matrices, the function is evaluated element wise. + * @param y Second value to nor + */ + nor( + this: MathJsChain< + number | BigNumber | bigint | Complex | Unit | MathCollection + >, + y: number | BigNumber | bigint | Complex | Unit | MathCollection + ): MathJsChain + /** * Logical xor. Test whether one and only one value is defined with a * nonzero/nonempty value. For matrices, the function is evaluated @@ -7592,6 +7618,7 @@ export const { and, not, or, + nor, xor, // matrix functions From a123ac0ada67d7e21c03c2ce81fa23f0258c7e9e Mon Sep 17 00:00:00 2001 From: Kryonn Date: Fri, 31 Oct 2025 11:53:45 -0300 Subject: [PATCH 05/12] code: nor final update 2 --- src/function/logical/nor.js | 9 +++++---- src/utils/latex.js | 4 +++- test/unit-tests/function/logical/nor.test.js | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/function/logical/nor.js b/src/function/logical/nor.js index 515c98744d..fb6ef0dc5e 100644 --- a/src/function/logical/nor.js +++ b/src/function/logical/nor.js @@ -1,6 +1,6 @@ import { createMatAlgo03xDSf } from '../../type/matrix/utils/matAlgo03xDSf.js' import { createMatAlgo12xSfs } from '../../type/matrix/utils/matAlgo12xSfs.js' -import { createMatAlgo05xSfSf } from '../../type/matrix/utils/matAlgo05xSfSf.js' +import { createMatAlgo07xSSf } from '../../type/matrix/utils/matAlgo07xSSf.js' import { factory } from '../../utils/factory.js' import { createMatrixAlgorithmSuite } from '../../type/matrix/utils/matrixAlgorithmSuite.js' import { norNumber } from '../../plain/number/logical.js' @@ -10,13 +10,14 @@ const dependencies = [ 'typed', 'matrix', 'equalScalar', + 'SparseMatrix', 'DenseMatrix', 'concat' ] -export const createNor = /* #__PURE__ */ factory(name, dependencies, ({ typed, matrix, equalScalar, DenseMatrix, concat }) => { +export const createNor = /* #__PURE__ */ factory(name, dependencies, ({ typed, matrix, SparseMatrix, DenseMatrix, concat }) => { const matAlgo03xDSf = createMatAlgo03xDSf({ typed }) - const matAlgo05xSfSf = createMatAlgo05xSfSf({ typed, equalScalar }) + const matAlgo07xSSf = createMatAlgo07xSSf({ typed, SparseMatrix }) const matAlgo12xSfs = createMatAlgo12xSfs({ typed, DenseMatrix }) const matrixAlgorithmSuite = createMatrixAlgorithmSuite({ typed, matrix, concat }) @@ -67,7 +68,7 @@ export const createNor = /* #__PURE__ */ factory(name, dependencies, ({ typed, m (x, y) => self(x.value || 0, y.value || 0)) }, matrixAlgorithmSuite({ - SS: matAlgo05xSfSf, + SS: matAlgo07xSSf, DS: matAlgo03xDSf, Ss: matAlgo12xSfs }) diff --git a/src/utils/latex.js b/src/utils/latex.js index 6ae2dc3b43..a8c18be8ac 100644 --- a/src/utils/latex.js +++ b/src/utils/latex.js @@ -106,7 +106,8 @@ export const latexOperators = { bitOr: '|', and: '\\wedge', xor: '\\veebar', - or: '\\vee' + or: '\\vee', + nor: '\\downarrow' } export const latexFunctions = { @@ -181,6 +182,7 @@ export const latexFunctions = { and: { 2: `\\left(\${args[0]}${latexOperators.and}\${args[1]}\\right)` }, not: { 1: latexOperators.not + '\\left(${args[0]}\\right)' }, or: { 2: `\\left(\${args[0]}${latexOperators.or}\${args[1]}\\right)` }, + nor: { 2: `\\left(\${args[0]}${latexOperators.nor}\${args[1]}\\right)` }, xor: { 2: `\\left(\${args[0]}${latexOperators.xor}\${args[1]}\\right)` }, // matrix diff --git a/test/unit-tests/function/logical/nor.test.js b/test/unit-tests/function/logical/nor.test.js index 4256e32d3d..75ea75c793 100644 --- a/test/unit-tests/function/logical/nor.test.js +++ b/test/unit-tests/function/logical/nor.test.js @@ -231,6 +231,6 @@ describe('nor', function () { it('should LaTeX nor', function () { const expression = math.parse('nor(1,2)') - assert.strictEqual(expression.toTex(), '\\left(1\\2\\right)') + assert.strictEqual(expression.toTex(), '\\left(1\\downarrow2\\right)') }) }) From 1f28cbd490aac9398c9d14d45c8b7608886bdc4c Mon Sep 17 00:00:00 2001 From: Kryonn Date: Tue, 4 Nov 2025 23:18:17 -0300 Subject: [PATCH 06/12] code: fix nor docs --- AUTHORS | 1 + src/expression/embeddedDocs/function/logical/nor.js | 8 ++++---- src/factoriesAny.js | 1 - src/function/logical/nor.js | 3 +-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/AUTHORS b/AUTHORS index 4fd2767fc0..9d1affcb2f 100644 --- a/AUTHORS +++ b/AUTHORS @@ -278,5 +278,6 @@ kyle-compute DongKwanKho <70864292+dodokw@users.noreply.github.com> Ikem Peter Josh Kelley +Kryonn # Generated by tools/update-authors.js diff --git a/src/expression/embeddedDocs/function/logical/nor.js b/src/expression/embeddedDocs/function/logical/nor.js index 1556e478f0..cb21a77d2b 100644 --- a/src/expression/embeddedDocs/function/logical/nor.js +++ b/src/expression/embeddedDocs/function/logical/nor.js @@ -7,11 +7,11 @@ export const norDocs = { ], description: 'Logical nor. Test if both values are zero', examples: [ - 'true nor false', - 'false nor false', - '0 nor 4' + 'nor(true, false)', + 'nor(false, false)', + 'nor(0, 4)' ], seealso: [ - 'not', 'and', 'xor', 'or', 'nand' + 'not', 'or', 'xor' ] } diff --git a/src/factoriesAny.js b/src/factoriesAny.js index 8dcec42679..9e336d2919 100644 --- a/src/factoriesAny.js +++ b/src/factoriesAny.js @@ -130,7 +130,6 @@ export { createLeftShift } from './function/bitwise/leftShift.js' export { createRightArithShift } from './function/bitwise/rightArithShift.js' export { createRightLogShift } from './function/bitwise/rightLogShift.js' export { createAnd } from './function/logical/and.js' -export { createNand } from './function/logical/nand.js' export { createCompare } from './function/relational/compare.js' export { createCompareNatural } from './function/relational/compareNatural.js' export { createCompareText } from './function/relational/compareText.js' diff --git a/src/function/logical/nor.js b/src/function/logical/nor.js index fb6ef0dc5e..d65a366dae 100644 --- a/src/function/logical/nor.js +++ b/src/function/logical/nor.js @@ -9,7 +9,6 @@ const name = 'nor' const dependencies = [ 'typed', 'matrix', - 'equalScalar', 'SparseMatrix', 'DenseMatrix', 'concat' @@ -42,7 +41,7 @@ export const createNor = /* #__PURE__ */ factory(name, dependencies, ({ typed, m * * See also: * - * and, nand, or, not, xor + * and, or, not, xor * * @param {number | BigNumber | bigint | Complex | Unit | Array | Matrix} x First value to check * @param {number | BigNumber | bigint | Complex | Unit | Array | Matrix} y Second value to check From 843b371b1e97d2183d75518db3f505ad2f55242c Mon Sep 17 00:00:00 2001 From: Kryonn Date: Thu, 6 Nov 2025 11:25:48 -0300 Subject: [PATCH 07/12] code: fix NOR and implement NAND --- src/expression/embeddedDocs/embeddedDocs.js | 2 + .../embeddedDocs/function/logical/nand.js | 17 ++ src/factoriesAny.js | 1 + src/factoriesNumber.js | 2 + src/function/logical/nand.js | 51 +++++ src/function/logical/nor.js | 38 +--- src/utils/latex.js | 2 + test/unit-tests/function/logical/nand.test.js | 210 ++++++++++++++++++ 8 files changed, 292 insertions(+), 31 deletions(-) create mode 100644 src/expression/embeddedDocs/function/logical/nand.js create mode 100644 src/function/logical/nand.js create mode 100644 test/unit-tests/function/logical/nand.test.js diff --git a/src/expression/embeddedDocs/embeddedDocs.js b/src/expression/embeddedDocs/embeddedDocs.js index 7b7cc31168..7303f8e3fe 100644 --- a/src/expression/embeddedDocs/embeddedDocs.js +++ b/src/expression/embeddedDocs/embeddedDocs.js @@ -111,6 +111,7 @@ import { helpDocs } from './function/expression/help.js' import { distanceDocs } from './function/geometry/distance.js' import { intersectDocs } from './function/geometry/intersect.js' import { andDocs } from './function/logical/and.js' +import { nandDocs } from './function/logical/nand.js' import { notDocs } from './function/logical/not.js' import { nullishDocs } from './function/logical/nullish.js' import { orDocs } from './function/logical/or.js' @@ -448,6 +449,7 @@ export const embeddedDocs = { // functions - logical and: andDocs, + nand: nandDocs, not: notDocs, nullish: nullishDocs, or: orDocs, diff --git a/src/expression/embeddedDocs/function/logical/nand.js b/src/expression/embeddedDocs/function/logical/nand.js new file mode 100644 index 0000000000..696f0d53a7 --- /dev/null +++ b/src/expression/embeddedDocs/function/logical/nand.js @@ -0,0 +1,17 @@ +export const nandDocs = { + name: 'nand', + category: 'Logical', + syntax: [ + 'x nand y', + 'nand(x, y)' + ], + description: 'Logical nand. Test whether at least one of values is zero.', + examples: [ + 'nand(true, false)', + 'nand(true, true)', + 'nand(2, 4)' + ], + seealso: [ + 'not', 'or', 'xor' + ] +} diff --git a/src/factoriesAny.js b/src/factoriesAny.js index 9e336d2919..4941b9296f 100644 --- a/src/factoriesAny.js +++ b/src/factoriesAny.js @@ -71,6 +71,7 @@ export { createNot } from './function/logical/not.js' export { createNullish } from './function/logical/nullish.js' export { createOr } from './function/logical/or.js' export { createNor } from './function/logical/nor.js' +export { createNand } from './function/logical/nand.js' export { createXor } from './function/logical/xor.js' export { createConcat } from './function/matrix/concat.js' export { createColumn } from './function/matrix/column.js' diff --git a/src/factoriesNumber.js b/src/factoriesNumber.js index 182fed7aa1..bad7eb238b 100644 --- a/src/factoriesNumber.js +++ b/src/factoriesNumber.js @@ -52,6 +52,7 @@ import { notNumber, nthRootNumber, orNumber, + nandNumber, powNumber, rightArithShiftNumber, rightLogShiftNumber, @@ -205,6 +206,7 @@ export { createParserClass } from './expression/Parser.js' // logical export const createAnd = /* #__PURE__ */ createNumberFactory('and', andNumber) +export const createNand = /* #__PURE__ */ createNumberFactory('nand', nandNumber) export const createNot = /* #__PURE__ */ createNumberFactory('not', notNumber) export const createOr = /* #__PURE__ */ createNumberFactory('or', orNumber) export const createXor = /* #__PURE__ */ createNumberFactory('xor', xorNumber) diff --git a/src/function/logical/nand.js b/src/function/logical/nand.js new file mode 100644 index 0000000000..9eb5ac1e36 --- /dev/null +++ b/src/function/logical/nand.js @@ -0,0 +1,51 @@ +import { factory } from '../../utils/factory.js' +import { nandNumber } from '../../plain/number/logical.js' + +const name = 'nand' +const dependencies = [ + 'typed', + 'and', + 'not' +] + +export const createNand = /* #__PURE__ */ factory(name, dependencies, ({ typed, and, not }) => { + /** + * Logical `nand`. Test if at least one of the inputs is zero. + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.nand(x, y) + * + * Examples: + * + * math.nand(2, 4) // returns false + * + * a = [2, 5, 0] + * b = [0, 22, 0] + * c = 0 + * + * math.nand(a, b) // returns [true, false, true] + * math.nand(b, c) // returns [true, true, true] + * + * See also: + * + * and, or, not, xor + * + * @param {number | BigNumber | bigint | Complex | Unit | Array | Matrix} x First value to check + * @param {number | BigNumber | bigint | Complex | Unit | Array | Matrix} y Second value to check + * @return {boolean | Array | Matrix} + * Returns true when at least one of the inputs is zero + */ + return typed( + name, + { + 'number, number': nandNumber, + 'bigint, bigint': nandNumber, + + 'any, any': function (x, y) { + return not(and(x, y)) + } + } + ) +}) diff --git a/src/function/logical/nor.js b/src/function/logical/nor.js index d65a366dae..ed2e913d9c 100644 --- a/src/function/logical/nor.js +++ b/src/function/logical/nor.js @@ -1,25 +1,14 @@ -import { createMatAlgo03xDSf } from '../../type/matrix/utils/matAlgo03xDSf.js' -import { createMatAlgo12xSfs } from '../../type/matrix/utils/matAlgo12xSfs.js' -import { createMatAlgo07xSSf } from '../../type/matrix/utils/matAlgo07xSSf.js' import { factory } from '../../utils/factory.js' -import { createMatrixAlgorithmSuite } from '../../type/matrix/utils/matrixAlgorithmSuite.js' import { norNumber } from '../../plain/number/logical.js' const name = 'nor' const dependencies = [ 'typed', - 'matrix', - 'SparseMatrix', - 'DenseMatrix', - 'concat' + 'or', + 'not' ] -export const createNor = /* #__PURE__ */ factory(name, dependencies, ({ typed, matrix, SparseMatrix, DenseMatrix, concat }) => { - const matAlgo03xDSf = createMatAlgo03xDSf({ typed }) - const matAlgo07xSSf = createMatAlgo07xSSf({ typed, SparseMatrix }) - const matAlgo12xSfs = createMatAlgo12xSfs({ typed, DenseMatrix }) - const matrixAlgorithmSuite = createMatrixAlgorithmSuite({ typed, matrix, concat }) - +export const createNor = /* #__PURE__ */ factory(name, dependencies, ({ typed, or, not }) => { /** * Logical `nor`. Test if both of values are defined with zero. * For matrices, the function is evaluated element wise. @@ -52,24 +41,11 @@ export const createNor = /* #__PURE__ */ factory(name, dependencies, ({ typed, m name, { 'number, number': norNumber, - - 'Complex, Complex': function (x, y) { - return !((x.re !== 0 || x.im !== 0) || (y.re !== 0 || y.im !== 0)) - }, - - 'BigNumber, BigNumber': function (x, y) { - return !((!x.isZero() && !x.isNaN()) || (!y.isZero() && !y.isNaN())) - }, - 'bigint, bigint': norNumber, - 'Unit, Unit': typed.referToSelf(self => - (x, y) => self(x.value || 0, y.value || 0)) - }, - matrixAlgorithmSuite({ - SS: matAlgo07xSSf, - DS: matAlgo03xDSf, - Ss: matAlgo12xSfs - }) + 'any, any': function (x, y) { + return not(or(x, y)) + } + } ) }) diff --git a/src/utils/latex.js b/src/utils/latex.js index a8c18be8ac..8737397fb6 100644 --- a/src/utils/latex.js +++ b/src/utils/latex.js @@ -105,6 +105,7 @@ export const latexOperators = { bitXor: '\\underline{|}', bitOr: '|', and: '\\wedge', + nand: '\\uparrow', xor: '\\veebar', or: '\\vee', nor: '\\downarrow' @@ -180,6 +181,7 @@ export const latexFunctions = { // logical and: { 2: `\\left(\${args[0]}${latexOperators.and}\${args[1]}\\right)` }, + nand: { 2: `\\left(\${args[0]}${latexOperators.nand}\${args[1]}\\right)` }, not: { 1: latexOperators.not + '\\left(${args[0]}\\right)' }, or: { 2: `\\left(\${args[0]}${latexOperators.or}\${args[1]}\\right)` }, nor: { 2: `\\left(\${args[0]}${latexOperators.nor}\${args[1]}\\right)` }, diff --git a/test/unit-tests/function/logical/nand.test.js b/test/unit-tests/function/logical/nand.test.js new file mode 100644 index 0000000000..17c9167d24 --- /dev/null +++ b/test/unit-tests/function/logical/nand.test.js @@ -0,0 +1,210 @@ +// test nand +import assert from 'assert' + +import math from '../../../../src/defaultInstance.js' +const bignumber = math.bignumber +const complex = math.complex +const matrix = math.matrix +const sparse = math.sparse +const unit = math.unit +const nand = math.nand + +describe('nand', function () { + it('should nand two numbers correctly', function () { + assert.strictEqual(nand(1, 1), false) + assert.strictEqual(nand(-1, 1), false) + assert.strictEqual(nand(-1, -1), false) + assert.strictEqual(nand(0, -1), true) + assert.strictEqual(nand(1, 0), true) + assert.strictEqual(nand(1, NaN), true) + assert.strictEqual(nand(NaN, 1), true) + assert.strictEqual(nand(1e10, 0.019209), false) + assert.strictEqual(nand(-1.0e-100, 1.0e-100), false) + assert.strictEqual(nand(Infinity, -Infinity), false) + }) + + it('should nand two complex numbers', function () { + assert.strictEqual(nand(complex(1, 1), complex(1, 1)), false) + assert.strictEqual(nand(complex(0, 1), complex(1, 1)), false) + assert.strictEqual(nand(complex(1, 0), complex(1, 1)), false) + assert.strictEqual(nand(complex(1, 1), complex(0, 1)), false) + assert.strictEqual(nand(complex(1, 1), complex(1, 0)), false) + assert.strictEqual(nand(complex(1, 0), complex(1, 0)), false) + assert.strictEqual(nand(complex(0, 1), complex(0, 1)), false) + assert.strictEqual(nand(complex(0, 0), complex(1, 1)), true) + assert.strictEqual(nand(complex(0, 0), complex(0, 1)), true) + assert.strictEqual(nand(complex(0, 0), complex(1, 0)), true) + assert.strictEqual(nand(complex(1, 1), complex(0, 0)), true) + assert.strictEqual(nand(complex(0, 1), complex(0, 0)), true) + assert.strictEqual(nand(complex(1, 0), complex(0, 0)), true) + assert.strictEqual(nand(complex(), complex(1, 1)), true) + assert.strictEqual(nand(complex(0), complex(1, 1)), true) + assert.strictEqual(nand(complex(1), complex(1, 1)), false) + assert.strictEqual(nand(complex(1, 1), complex()), true) + assert.strictEqual(nand(complex(1, 1), complex(0)), true) + assert.strictEqual(nand(complex(1, 1), complex(1)), false) + }) + + it('should nand mixed numbers nand complex numbers', function () { + assert.strictEqual(nand(complex(1, 1), 1), false) + assert.strictEqual(nand(complex(1, 1), 0), true) + assert.strictEqual(nand(1, complex(1, 1)), false) + assert.strictEqual(nand(0, complex(1, 1)), true) + assert.strictEqual(nand(complex(0, 0), 1), true) + assert.strictEqual(nand(1, complex(0, 0)), true) + }) + + it('should nand two booleans', function () { + assert.strictEqual(nand(true, true), false) + assert.strictEqual(nand(true, false), true) + assert.strictEqual(nand(false, true), true) + assert.strictEqual(nand(false, false), true) + }) + + it('should nand mixed numbers nand booleans', function () { + assert.strictEqual(nand(2, true), false) + assert.strictEqual(nand(2, false), true) + assert.strictEqual(nand(0, true), true) + assert.strictEqual(nand(true, 2), false) + assert.strictEqual(nand(false, 2), true) + }) + + it('should nand bignumbers', function () { + assert.strictEqual(nand(bignumber(1), bignumber(1)), false) + assert.strictEqual(nand(bignumber(-1), bignumber(1)), false) + assert.strictEqual(nand(bignumber(-1), bignumber(-1)), false) + assert.strictEqual(nand(bignumber(0), bignumber(-1)), true) + assert.strictEqual(nand(bignumber(1), bignumber(0)), true) + assert.strictEqual(nand(bignumber(1), bignumber(NaN)), true) + assert.strictEqual(nand(bignumber(NaN), bignumber(1)), true) + assert.strictEqual(nand(bignumber('1e+10'), bignumber(0.19209)), false) + assert.strictEqual(nand(bignumber('-1.0e-100'), bignumber('1.0e-100')), false) + assert.strictEqual(nand(bignumber(Infinity), bignumber(-Infinity)), false) + }) + + it('should nand bigints', function () { + assert.strictEqual(nand(1n, 1n), false) + assert.strictEqual(nand(-1n, 1n), false) + assert.strictEqual(nand(-1n, -1n), false) + assert.strictEqual(nand(0n, -1n), true) + assert.strictEqual(nand(1n, 0n), true) + }) + + it('should nand mixed numbers nand bignumbers', function () { + assert.strictEqual(nand(bignumber(2), 3), false) + assert.strictEqual(nand(2, bignumber(2)), false) + assert.strictEqual(nand(0, bignumber(2)), true) + assert.strictEqual(nand(2, bignumber(0)), true) + assert.strictEqual(nand(bignumber(0), 2), true) + assert.strictEqual(nand(bignumber(2), 0), true) + }) + + it('should nand mixed numbers nand bigints', function () { + assert.strictEqual(nand(2n, 3), false) + assert.strictEqual(nand(2, 2n), false) + assert.strictEqual(nand(0, 2n), true) + assert.strictEqual(nand(2, 0n), true) + assert.strictEqual(nand(0n, 2), true) + assert.strictEqual(nand(2n, 0), true) + }) + + it('should nand two units', function () { + assert.strictEqual(nand(unit('100cm'), unit('10inch')), false) + assert.strictEqual(nand(unit('100cm'), unit('0 inch')), true) + assert.strictEqual(nand(unit('0cm'), unit('1m')), true) + assert.strictEqual(nand(unit('m'), unit('1m')), true) + assert.strictEqual(nand(unit('1dm'), unit('m')), true) + assert.strictEqual(nand(unit('-100cm'), unit('-10inch')), false) + assert.strictEqual(nand(unit(5, 'km'), unit(100, 'gram')), false) + assert.strictEqual(nand(unit(5, 'km'), unit(0, 'gram')), true) + assert.strictEqual(nand(unit(0, 'km'), unit(100, 'gram')), true) + + assert.strictEqual(nand(unit(bignumber(0), 'm'), unit(bignumber(0), 'm')), true) + assert.strictEqual(nand(unit(bignumber(1), 'm'), unit(bignumber(0), 'm')), true) + assert.strictEqual(nand(unit(bignumber(0), 'm'), unit(bignumber(1), 'm')), true) + assert.strictEqual(nand(unit(bignumber(1), 'm'), unit(bignumber(1), 'm')), false) + }) + + describe('Array', function () { + it('should nand array - scalar', function () { + assert.deepStrictEqual(nand(10, [0, 2]), [true, false]) + assert.deepStrictEqual(nand([0, 2], 10), [true, false]) + }) + + it('should nand array - array', function () { + assert.deepStrictEqual(nand([0, 1, 0, 12], [0, 0, 1, 22]), [true, true, true, false]) + assert.deepStrictEqual(nand([], []), []) + }) + + it('should nand broadcastable arrays', function () { + assert.deepStrictEqual(nand([[0, 1, 0, 12]], [[0], [0], [1], [22]]), [[true, true, true, true], [true, true, true, true], [true, false, true, false], [true, false, true, false]]) + }) + + it('should nand array - dense matrix', function () { + assert.deepStrictEqual(nand([0, 1, 0, 12], matrix([0, 0, 1, 22])), matrix([true, true, true, false])) + assert.deepStrictEqual(nand([], matrix([])), matrix([])) + }) + + it('should nand array - sparse matrix', function () { + assert.deepStrictEqual(nand([[0, 1], [0, 12]], sparse([[0, 0], [1, 22]])), sparse([[true, true], [true, false]])) + }) + }) + + describe('DenseMatrix', function () { + it('should nand dense matrix - scalar', function () { + assert.deepStrictEqual(nand(10, matrix([0, 2])), matrix([true, false])) + assert.deepStrictEqual(nand(matrix([0, 2]), 10), matrix([true, false])) + }) + + it('should nand dense matrix - array', function () { + assert.deepStrictEqual(nand(matrix([0, 1, 0, 12]), [0, 0, 1, 22]), matrix([true, true, true, false])) + assert.deepStrictEqual(nand(matrix([]), []), matrix([])) + }) + + it('should nand dense matrix - dense matrix', function () { + assert.deepStrictEqual(nand(matrix([0, 1, 0, 12]), matrix([0, 0, 1, 22])), matrix([true, true, true, false])) + assert.deepStrictEqual(nand(matrix([]), matrix([])), matrix([])) + }) + + it('should nand dense matrix - sparse matrix', function () { + assert.deepStrictEqual(nand(matrix([[0, 1], [0, 12]]), sparse([[0, 0], [1, 22]])), sparse([[true, true], [true, false]])) + }) + }) + + describe('SparseMatrix', function () { + it('should nand sparse matrix - scalar', function () { + assert.deepStrictEqual(nand(10, sparse([[0], [2]])), sparse([[true], [false]])) + assert.deepStrictEqual(nand(sparse([[0], [2]]), 10), sparse([[true], [false]])) + }) + + it('should nand sparse matrix - array', function () { + assert.deepStrictEqual(nand(sparse([[0, 1], [0, 12]]), [[0, 0], [1, 22]]), sparse([[true, true], [true, false]])) + }) + + it('should nand sparse matrix - dense matrix', function () { + assert.deepStrictEqual(nand(sparse([[0, 1], [0, 12]]), matrix([[0, 0], [1, 22]])), sparse([[true, true], [true, false]])) + }) + + it('should nand sparse matrix - sparse matrix', function () { + assert.deepStrictEqual(nand(sparse([[0, 1], [0, 12]]), sparse([[0, 0], [1, 22]])), sparse([[true, true], [true, false]])) + }) + }) + + it('should throw an error in case of invalid number of arguments', function () { + assert.throws(function () { nand(1) }, /TypeError: Too few arguments/) + assert.throws(function () { nand(1, 2, 3) }, /TypeError: Too many arguments/) + }) + + it('should throw an error in case of invalid type of arguments', function () { + assert.throws(function () { nand(2, null) }, /TypeError: Unexpected type of argument/) + assert.throws(function () { nand(new Date(), false) }, /TypeError: Unexpected type of argument/) + assert.throws(function () { nand(false, new Date()) }, /TypeError: Unexpected type of argument/) + assert.throws(function () { nand(false, undefined) }, /TypeError: Unexpected type of argument/) + assert.throws(function () { nand(undefined, false) }, /TypeError: Unexpected type of argument/) + }) + + it('should LaTeX nand', function () { + const expression = math.parse('nand(1,2)') + assert.strictEqual(expression.toTex(), '\\left(1\\uparrow2\\right)') + }) +}) From 6430d6148de2cacf070ab410a8bfe7989293a6f6 Mon Sep 17 00:00:00 2001 From: Kryonn Date: Thu, 6 Nov 2025 11:38:24 -0300 Subject: [PATCH 08/12] code: Update index.d.ts --- types/index.d.ts | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/types/index.d.ts b/types/index.d.ts index 12989abed1..466000b72d 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -360,6 +360,7 @@ export interface ObjectNodeCtor { export type OperatorNodeMap = { xor: 'xor' and: 'and' + nand: 'nand' or: 'or' nor: 'nor' bitOr: '|' @@ -1880,6 +1881,18 @@ export interface MathJsInstance extends MathJsFactory { y: number | BigNumber | bigint | Complex | Unit | MathCollection ): boolean | MathCollection + /** + * Logical nand. Test whether at least one of values is zero. + * For matrices, the function is evaluated element wise. + * @param x First value to nand + * @param y Second value to nand + * @returns Returns true when at least of values is zero or empty balue. + */ + nand( + x: number | BigNumber | bigint | Complex | Unit | MathCollection, + y: number | BigNumber | bigint | Complex | Unit | MathCollection + ): boolean | MathCollection + /** * Logical not. Flips boolean value of a given parameter. For matrices, * the function is evaluated element wise. @@ -4093,6 +4106,7 @@ export const { // logical dependencies andDependencies, + nandDependencies, notDependencies, orDependencies, norDependencies, @@ -5979,6 +5993,18 @@ export interface MathJsChain { * Logical functions ************************************************************************/ + /** + * Logical nand. Test whether at least one of values is zero. + * For matrices, the function is evaluated element wise. + * @param y Second value to nand + */ + nand( + this: MathJsChain< + number | BigNumber | bigint | Complex | Unit | MathCollection + >, + y: number | BigNumber | bigint | Complex | Unit | MathCollection + ): MathJsChain + /** * Logical and. Test whether two values are both defined with a * nonzero/nonempty value. For matrices, the function is evaluated @@ -7635,6 +7661,7 @@ export const { // logical and, + nand, not, or, nor, From f084bd8d95e18db6043b2705ceed6bd1cced0a99 Mon Sep 17 00:00:00 2001 From: Kryonn Date: Mon, 10 Nov 2025 15:55:27 -0300 Subject: [PATCH 09/12] code: finish tasks --- src/expression/operators.js | 12 +++ src/expression/parse.js | 16 ++-- test/typescript-tests/testTypes.ts | 96 ++++++++++++++++++++++++ test/unit-tests/expression/parse.test.js | 67 ++++++++++++++++- 4 files changed, 185 insertions(+), 6 deletions(-) diff --git a/src/expression/operators.js b/src/expression/operators.js index 8076f70aeb..4460a7bb56 100644 --- a/src/expression/operators.js +++ b/src/expression/operators.js @@ -38,6 +38,12 @@ export const properties = [ op: 'or', associativity: 'left', associativeWith: [] + }, + // logical nor + 'OperatorNode:nor': { + op: 'nor', + associativity: 'left', + associativeWith: [] } }, { // logical xor @@ -52,6 +58,12 @@ export const properties = [ op: 'and', associativity: 'left', associativeWith: [] + }, + // logical nand + 'OperatorNode:nand': { + op: 'nand', + associativity: 'left', + associativeWith: [] } }, { // bitwise or diff --git a/src/expression/parse.js b/src/expression/parse.js index ca5976a29b..93ebf99af0 100644 --- a/src/expression/parse.js +++ b/src/expression/parse.js @@ -174,7 +174,9 @@ export const createParse = /* #__PURE__ */ factory(name, dependencies, ({ and: true, xor: true, or: true, - not: true + nand: true, + not: true, + nor: true } const CONSTANTS = { @@ -756,15 +758,17 @@ export const createParse = /* #__PURE__ */ factory(name, dependencies, ({ /** * logical or, 'x or y' + * logical nor, 'x nor y' * @return {Node} node * @private */ function parseLogicalOr (state) { let node = parseLogicalXor(state) - while (state.token === 'or') { // eslint-disable-line no-unmodified-loop-condition + while (state.token === 'or' || state.token === 'nor') { // eslint-disable-line no-unmodified-loop-condition + const op = state.token getTokenSkipNewline(state) - node = new OperatorNode('or', 'or', [node, parseLogicalXor(state)]) + node = new OperatorNode(op, op, [node, parseLogicalXor(state)]) } return node @@ -788,15 +792,17 @@ export const createParse = /* #__PURE__ */ factory(name, dependencies, ({ /** * logical and, 'x and y' + * logical nand, 'x nand y' * @return {Node} node * @private */ function parseLogicalAnd (state) { let node = parseBitwiseOr(state) - while (state.token === 'and') { // eslint-disable-line no-unmodified-loop-condition + while (state.token === 'and' || state.token === 'nand') { // eslint-disable-line no-unmodified-loop-condition + const op = state.token getTokenSkipNewline(state) - node = new OperatorNode('and', 'and', [node, parseBitwiseOr(state)]) + node = new OperatorNode(op, op, [node, parseBitwiseOr(state)]) } return node diff --git a/test/typescript-tests/testTypes.ts b/test/typescript-tests/testTypes.ts index 9e2d4b684c..c62eec285c 100644 --- a/test/typescript-tests/testTypes.ts +++ b/test/typescript-tests/testTypes.ts @@ -3176,3 +3176,99 @@ Match types of exact positional arguments. expectTypeOf(mixArray3).toMatchTypeOf>() expectTypeOf(unitArray3).toMatchTypeOf>() } + +/** + * NAND examples + */ +{ + const math = create(all, {}) + + // number input + assert.strictEqual(math.nand(3, 2), false) + assert.strictEqual(math.nand(3, 0), true) + assert.strictEqual(math.nand(0, 2), true) + assert.strictEqual(math.nand(0, 0), true) + + // bignumber input + assert.deepStrictEqual(math.nand(math.bignumber(4), math.bignumber(2)), false) + assert.deepStrictEqual(math.nand(math.bignumber(3), 0), true) + assert.deepStrictEqual(math.nand(math.bignumber(0), math.bignumber(0)), true) + + // Complex input + const a = math.complex(3.24, -2.71) + const b = math.complex(0, 0) + assert.deepStrictEqual(math.nand(a, a), false) + assert.deepStrictEqual(math.nand(a, b), true) + assert.deepStrictEqual(math.nand(b, b), true) + + // unit input + const u1 = math.unit(3.2, 'cm') + const u2 = math.unit('cm') + const u3 = math.unit(5.51, 'cm') + assert.deepStrictEqual(math.nand(u1, u2), true) + assert.deepStrictEqual(math.nand(u1, u3), false) + + // array input + assert.deepStrictEqual(math.nand([3.2, 3.8, -4.7], 2), [false, false, false]) + assert.deepStrictEqual(math.nand([3.2, 3.8, -4.7], 0), [true, true, true]) + assert.deepStrictEqual(math.nand([3.2, 3.8, 0], 7), [false, false, true]) + assert.deepStrictEqual(math.nand([3.21, 3.82, -4.71], math.bignumber(1)), [ + false, + false, + false + ]) + + // matrix of decimals + assert.deepStrictEqual( + math.nand(math.matrix([1, 4, 0, 0]), math.matrix([1, 0, 6, 0])).valueOf(), + [false, true, true, true] + ) +} + +/** + * NOR examples + */ +{ + const math = create(all, {}) + + // number input + assert.strictEqual(math.nor(3, 2), false) + assert.strictEqual(math.nor(3, 0), false) + assert.strictEqual(math.nor(0, 2), false) + assert.strictEqual(math.nor(0, 0), true) + + // bignumber input + assert.deepStrictEqual(math.nor(math.bignumber(4), math.bignumber(2)), false) + assert.deepStrictEqual(math.nor(math.bignumber(3), 0), false) + assert.deepStrictEqual(math.nor(math.bignumber(0), math.bignumber(0)), true) + + // Complex input + const a = math.complex(3.24, -2.71) + const b = math.complex(0, 0) + assert.deepStrictEqual(math.nor(a, a), false) + assert.deepStrictEqual(math.nor(a, b), false) + assert.deepStrictEqual(math.nor(b, b), true) + + // unit input + const u1 = math.unit(3.2, 'cm') + const u2 = math.unit('cm') + const u3 = math.unit(5.51, 'cm') + assert.deepStrictEqual(math.nor(u1, u2), false) + assert.deepStrictEqual(math.nor(u1, u3), false) + + // array input + assert.deepStrictEqual(math.nor([3.2, 3.8, -4.7], 2), [false, false, false]) + assert.deepStrictEqual(math.nor([3.2, 3.8, 0], 0), [false, false, true]) + assert.deepStrictEqual(math.nor([3.2, 3.8, 0], 7), [false, false, false]) + assert.deepStrictEqual(math.nor([3.21, 3.82, -4.71], math.bignumber(1)), [ + false, + false, + false + ]) + + // matrix of decimals + assert.deepStrictEqual( + math.nor(math.matrix([1, 4, 0, 0]), math.matrix([1, 0, 6, 0])).valueOf(), + [false, false, false, true] + ) +} diff --git a/test/unit-tests/expression/parse.test.js b/test/unit-tests/expression/parse.test.js index 9ec806ed63..5929c996ad 100644 --- a/test/unit-tests/expression/parse.test.js +++ b/test/unit-tests/expression/parse.test.js @@ -1236,7 +1236,7 @@ describe('parse', function () { }) it('should create an object with unquoted keys that are keywords', function () { - assert.deepStrictEqual(parseAndEval('{ mod: 1, and: 1, not: 1, or: 1, xor: 1, to: 1, in: 1 }'), { mod: 1, and: 1, not: 1, or: 1, xor: 1, to: 1, in: 1 }) + assert.deepStrictEqual(parseAndEval('{ mod: 1, and: 1, not: 1, or: 1, xor: 1, to: 1, in: 1, nor: 1, nand: 1 }'), { mod: 1, and: 1, not: 1, or: 1, xor: 1, to: 1, in: 1, nor: 1, nand: 1 }) }) it('should create an object with child object', function () { @@ -1925,6 +1925,24 @@ describe('parse', function () { assert.strictEqual(scope.a, false) }) + it('should parse logical nand', function () { + assert.strictEqual(parseAndEval('2 nand 6'), false) + assert.strictEqual(parseAndEval('2 nand 0'), true) + assert.strictEqual(parseAndEval('true nand true'), false) + assert.strictEqual(parseAndEval('true nand false'), true) + assert.strictEqual(parseAndEval('false nand true'), true) + assert.strictEqual(parseAndEval('false nand false'), true) + assert.throws(function () { parseAndEval('true nand undefined') }, TypeError) + }) + + it('should parse logical nand inside a function definition', function () { + const scope = {} + const f = parseAndEval('f(x) = x > 2 nand x < 4', scope) + assert.strictEqual(f(1), true) + assert.strictEqual(f(3), false) + assert.strictEqual(f(5), true) + }) + it('should always pass a Map as scope to a rawArgs function', function () { const myMath = math.create() function myFunction (args, _math, _scope) { @@ -1986,6 +2004,24 @@ describe('parse', function () { assert.deepStrictEqual(scope, { a: true }) }) + it('should parse logical nor', function () { + assert.strictEqual(parseAndEval('2 nor 6'), false) + assert.strictEqual(parseAndEval('2 nor 0'), false) + assert.strictEqual(parseAndEval('true nor true'), false) + assert.strictEqual(parseAndEval('true nor false'), false) + assert.strictEqual(parseAndEval('false nor true'), false) + assert.strictEqual(parseAndEval('false nor false'), true) + assert.throws(function () { parseAndEval('false nor undefined') }, TypeError) + }) + + it('should parse logical nor inside a function definition', function () { + const scope = {} + const f = parseAndEval('f(x) = x < 2 nor x > 4', scope) + assert.strictEqual(f(1), false) + assert.strictEqual(f(3), true) + assert.strictEqual(f(5), false) + }) + it('should parse logical not', function () { assert.strictEqual(parseAndEval('not 2'), false) assert.strictEqual(parseAndEval('not not 2'), true) @@ -2309,6 +2345,11 @@ describe('parse', function () { assert.strictEqual(parseAndEval('4 and 2 | 2'), true) }) + it('should respect precedence between bitwise or | and logical nand', function () { + assert.strictEqual(parseAndEval('2 | 2 nand 4'), false) + assert.strictEqual(parseAndEval('4 nand 2 | 2'), false) + }) + it('should respect precedence between bitwise xor ^| and bitwise or |', function () { assert.strictEqual(parseAndEval('4 ^| 6 | 2'), 2) assert.strictEqual(parseAndEval('2 | 4 ^| 6'), 2) @@ -2328,6 +2369,13 @@ describe('parse', function () { assert.strictEqual(parseAndEval('(true or true) and false'), false) }) + it('should respect precedence between logical nand and or', function () { + assert.strictEqual(parseAndEval('false nand true or true'), true) + assert.strictEqual(parseAndEval('false nand (true or true)'), true) + assert.strictEqual(parseAndEval('true or true nand false'), true) + assert.strictEqual(parseAndEval('(true or true) nand false'), true) + }) + it('should respect precedence of conditional operator and logical or', function () { const node = math.parse('1 or 0 ? 2 or 3 : 0 or 0') assert(node instanceof ConditionalNode) @@ -2337,6 +2385,22 @@ describe('parse', function () { assert.strictEqual(node.compile().evaluate(), true) }) + it('should respect precedence between logical and and nor', function () { + assert.strictEqual(parseAndEval('false and true nor true'), false) + assert.strictEqual(parseAndEval('false and (true nor true)'), false) + assert.strictEqual(parseAndEval('true nor true and false'), false) + assert.strictEqual(parseAndEval('(true nor true) and false'), false) + }) + + it('should respect precedence of conditional operator and logical nor', function () { + const node = math.parse('1 nor 0 ? 2 nor 3 : 0 nor 0') + assert(node instanceof ConditionalNode) + assert.strictEqual(node.condition.toString(), '1 nor 0') + assert.strictEqual(node.trueExpr.toString(), '2 nor 3') + assert.strictEqual(node.falseExpr.toString(), '0 nor 0') + assert.strictEqual(node.compile().evaluate(), true) + }) + it('should respect precedence of conditional operator and relational operators', function () { const node = math.parse('a == b ? a > b : a < b') assert(node instanceof ConditionalNode) @@ -2679,6 +2743,7 @@ describe('parse', function () { assert.strictEqual(parse('false and true').toString(), 'false and true') assert.strictEqual(parse('false xor true').toString(), 'false xor true') assert.strictEqual(parse('false or true').toString(), 'false or true') + assert.strictEqual(parse('false nor true').toString(), 'false nor true') assert.strictEqual(parse('not true').toString(), 'not true') assert.strictEqual(parse('5!').toString(), '5!') }) From 432564378b70e7c51a73837a7f00f1f4231f0efc Mon Sep 17 00:00:00 2001 From: Kryonn Date: Wed, 12 Nov 2025 08:02:40 -0300 Subject: [PATCH 10/12] code: fix test and functions --- src/expression/operators.js | 12 ++++++------ src/expression/parse.js | 18 +++++++++--------- test/unit-tests/expression/parse.test.js | 24 +++++++++++++++--------- 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/expression/operators.js b/src/expression/operators.js index 4460a7bb56..97622ae9e6 100644 --- a/src/expression/operators.js +++ b/src/expression/operators.js @@ -39,9 +39,9 @@ export const properties = [ associativity: 'left', associativeWith: [] }, - // logical nor - 'OperatorNode:nor': { - op: 'nor', + // logical nand + 'OperatorNode:nand': { + op: 'nand', associativity: 'left', associativeWith: [] } @@ -59,9 +59,9 @@ export const properties = [ associativity: 'left', associativeWith: [] }, - // logical nand - 'OperatorNode:nand': { - op: 'nand', + // logical nor + 'OperatorNode:nor': { + op: 'nor', associativity: 'left', associativeWith: [] } diff --git a/src/expression/parse.js b/src/expression/parse.js index 93ebf99af0..0c427b0254 100644 --- a/src/expression/parse.js +++ b/src/expression/parse.js @@ -728,7 +728,7 @@ export const createParse = /* #__PURE__ */ factory(name, dependencies, ({ * @private */ function parseConditional (state) { - let node = parseLogicalOr(state) + let node = parseLogicalOrNand(state) while (state.token === '?') { // eslint-disable-line no-unmodified-loop-condition // set a conditional level, the range operator will be ignored as long @@ -758,14 +758,14 @@ export const createParse = /* #__PURE__ */ factory(name, dependencies, ({ /** * logical or, 'x or y' - * logical nor, 'x nor y' + * logical nand, 'x nand y' * @return {Node} node * @private */ - function parseLogicalOr (state) { + function parseLogicalOrNand (state) { let node = parseLogicalXor(state) - while (state.token === 'or' || state.token === 'nor') { // eslint-disable-line no-unmodified-loop-condition + while (state.token === 'or' || state.token === 'nand') { // eslint-disable-line no-unmodified-loop-condition const op = state.token getTokenSkipNewline(state) node = new OperatorNode(op, op, [node, parseLogicalXor(state)]) @@ -780,11 +780,11 @@ export const createParse = /* #__PURE__ */ factory(name, dependencies, ({ * @private */ function parseLogicalXor (state) { - let node = parseLogicalAnd(state) + let node = parseLogicalAndNor(state) while (state.token === 'xor') { // eslint-disable-line no-unmodified-loop-condition getTokenSkipNewline(state) - node = new OperatorNode('xor', 'xor', [node, parseLogicalAnd(state)]) + node = new OperatorNode('xor', 'xor', [node, parseLogicalAndNor(state)]) } return node @@ -792,14 +792,14 @@ export const createParse = /* #__PURE__ */ factory(name, dependencies, ({ /** * logical and, 'x and y' - * logical nand, 'x nand y' + * logical nor, 'x nor y' * @return {Node} node * @private */ - function parseLogicalAnd (state) { + function parseLogicalAndNor (state) { let node = parseBitwiseOr(state) - while (state.token === 'and' || state.token === 'nand') { // eslint-disable-line no-unmodified-loop-condition + while (state.token === 'and' || state.token === 'nor') { // eslint-disable-line no-unmodified-loop-condition const op = state.token getTokenSkipNewline(state) node = new OperatorNode(op, op, [node, parseBitwiseOr(state)]) diff --git a/test/unit-tests/expression/parse.test.js b/test/unit-tests/expression/parse.test.js index 5929c996ad..fee809bef9 100644 --- a/test/unit-tests/expression/parse.test.js +++ b/test/unit-tests/expression/parse.test.js @@ -2370,10 +2370,13 @@ describe('parse', function () { }) it('should respect precedence between logical nand and or', function () { - assert.strictEqual(parseAndEval('false nand true or true'), true) - assert.strictEqual(parseAndEval('false nand (true or true)'), true) - assert.strictEqual(parseAndEval('true or true nand false'), true) - assert.strictEqual(parseAndEval('(true or true) nand false'), true) + assert.strictEqual(parseAndEval('true nand false or true'), true) + assert.strictEqual(parseAndEval('true nand (false or true)'), false) + }) + + it('should respect precedence between logical nand and and', function () { + assert.strictEqual(parseAndEval('false and false nand true'), true) + assert.strictEqual(parseAndEval('false and (false nand true)'), false) }) it('should respect precedence of conditional operator and logical or', function () { @@ -2385,11 +2388,14 @@ describe('parse', function () { assert.strictEqual(node.compile().evaluate(), true) }) - it('should respect precedence between logical and and nor', function () { - assert.strictEqual(parseAndEval('false and true nor true'), false) - assert.strictEqual(parseAndEval('false and (true nor true)'), false) - assert.strictEqual(parseAndEval('true nor true and false'), false) - assert.strictEqual(parseAndEval('(true nor true) and false'), false) + it('should respect precedence between logical nor and or', function () { + assert.strictEqual(parseAndEval('true nor false or true'), true) + assert.strictEqual(parseAndEval('true nor (false or true)'), false) + }) + + it('should respect precedence between logical nor and and', function () { + assert.strictEqual(parseAndEval('false nor true and false'), false) + assert.strictEqual(parseAndEval('false nor (true and false)'), true) }) it('should respect precedence of conditional operator and logical nor', function () { From d9dc7d0e788f1ef99a4ff54cc63a467d4b4ce472 Mon Sep 17 00:00:00 2001 From: Kryonn Date: Tue, 9 Dec 2025 12:16:00 -0300 Subject: [PATCH 11/12] fix unit-tests --- AUTHORS | 1 + test/unit-tests/expression/parse.test.js | 30 +++++++++++++++++------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/AUTHORS b/AUTHORS index 0ac8b51218..4397456cbd 100644 --- a/AUTHORS +++ b/AUTHORS @@ -281,5 +281,6 @@ Josh Kelley Kryonn Richard Taylor NilsDietrich <61544566+NilsDietrich@users.noreply.github.com> +Kryonn <151884657+Kryonn@users.noreply.github.com> # Generated by tools/update-authors.js diff --git a/test/unit-tests/expression/parse.test.js b/test/unit-tests/expression/parse.test.js index fee809bef9..8bc7811d3a 100644 --- a/test/unit-tests/expression/parse.test.js +++ b/test/unit-tests/expression/parse.test.js @@ -2321,6 +2321,7 @@ describe('parse', function () { assert.strictEqual(parseAndEval('2 > 3 ? true : false'), false) assert.strictEqual(parseAndEval('2 == 3 ? true : false'), false) assert.strictEqual(parseAndEval('3 ? 2 + 4 : 2 - 1'), 6) + assert.strictEqual(parseAndEval('true ? false : false nand true'), false) assert.deepStrictEqual(parseAndEval('3 ? true : false; 22'), new ResultSet([22])) assert.deepStrictEqual(parseAndEval('3 ? 5cm to m : 5cm in mm'), new Unit(5, 'cm').to('m')) assert.deepStrictEqual(parseAndEval('2 == 4-2 ? [1,2] : false'), math.matrix([1, 2])) @@ -2346,8 +2347,7 @@ describe('parse', function () { }) it('should respect precedence between bitwise or | and logical nand', function () { - assert.strictEqual(parseAndEval('2 | 2 nand 4'), false) - assert.strictEqual(parseAndEval('4 nand 2 | 2'), false) + assert.strictEqual(parseAndEval('true nand true | true'), false) }) it('should respect precedence between bitwise xor ^| and bitwise or |', function () { @@ -2371,12 +2371,17 @@ describe('parse', function () { it('should respect precedence between logical nand and or', function () { assert.strictEqual(parseAndEval('true nand false or true'), true) - assert.strictEqual(parseAndEval('true nand (false or true)'), false) + assert.strictEqual(parseAndEval('false or true nand true'), false) }) it('should respect precedence between logical nand and and', function () { - assert.strictEqual(parseAndEval('false and false nand true'), true) - assert.strictEqual(parseAndEval('false and (false nand true)'), false) + assert.strictEqual(parseAndEval('true nand true and false'), true) + assert.strictEqual(parseAndEval('true nand false and false'), true) + }) + + it('should respect precedence between logical nand and xor', function () { + assert.strictEqual(parseAndEval('false nand false xor true'), true) + assert.strictEqual(parseAndEval('false nand true xor true'), true) }) it('should respect precedence of conditional operator and logical or', function () { @@ -2389,13 +2394,22 @@ describe('parse', function () { }) it('should respect precedence between logical nor and or', function () { - assert.strictEqual(parseAndEval('true nor false or true'), true) - assert.strictEqual(parseAndEval('true nor (false or true)'), false) + assert.strictEqual(parseAndEval('true or false nor true'), true) + assert.strictEqual(parseAndEval('true or true nor false'), true) + }) + + it('should respect precedence between logical nor and bitwise or |', function () { + assert.strictEqual(parseAndEval('true nor false | true'), false) + assert.strictEqual(parseAndEval('false nor false | true'), false) }) it('should respect precedence between logical nor and and', function () { assert.strictEqual(parseAndEval('false nor true and false'), false) - assert.strictEqual(parseAndEval('false nor (true and false)'), true) + assert.strictEqual(parseAndEval('true and false nor false'), true) + }) + + it('should respect precedence between logical nor and xor', function () { + assert.strictEqual(parseAndEval('false xor false nor true'), false) }) it('should respect precedence of conditional operator and logical nor', function () { From 61f8c45859091eed496afbaf41beefed273624f5 Mon Sep 17 00:00:00 2001 From: Glen Whitney Date: Tue, 9 Dec 2025 09:22:11 -0800 Subject: [PATCH 12/12] test: include nand in test/unit-tests/plain/number/logical --- test/unit-tests/plain/number/logical.test.js | 23 +++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/test/unit-tests/plain/number/logical.test.js b/test/unit-tests/plain/number/logical.test.js index 2eedd4ad24..ad42b7072d 100644 --- a/test/unit-tests/plain/number/logical.test.js +++ b/test/unit-tests/plain/number/logical.test.js @@ -1,17 +1,30 @@ import assert from 'assert' -import { norNumber } from '../../../../src/plain/number/logical.js' +import { nandNumber, norNumber } from '../../../../src/plain/number/logical.js' -describe('nor', function () { - it('should return true when both are 0', function () { +describe('nor/nand', function () { + it('nor should return true when both are 0', function () { assert.strictEqual(norNumber(0, 0), true) }) - it('should return false when one is 0 and the other is 1', function () { + it('nor should return false when one is 0 and the other is 1', function () { assert.strictEqual(norNumber(1, 0), false) assert.strictEqual(norNumber(0, 1), false) }) - it('should return false when both are 1', function () { + it('nor should return false when both are 1', function () { assert.strictEqual(norNumber(1, 1), false) }) + + it('nand should return true when both are 0', function () { + assert.strictEqual(nandNumber(0, 0), true) + }) + + it('nand should return true when one is 0 and the other is 1', function () { + assert.strictEqual(nandNumber(1, 0), true) + assert.strictEqual(nandNumber(0, 1), true) + }) + + it('nand should return false when both are 1', function () { + assert.strictEqual(nandNumber(1, 1), false) + }) })