diff --git a/README.md b/README.md index bb61a0b6a9..4936b2ebfb 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Math.js is an extensive math library for JavaScript and Node.js. It features a f ## Features -- Supports numbers, big numbers, complex numbers, fractions, units, strings, arrays, and matrices. +- Supports numbers, bignumbers, bigints, complex numbers, fractions, units, strings, arrays, and matrices. - Is compatible with JavaScript's built-in Math library. - Contains a flexible expression parser. - Does symbolic computation. @@ -118,13 +118,13 @@ The code of `mathjs` is written in ES modules, and requires all files to have a What mathjs tries to achieve is to offer an environment where you can do calculations with mixed data types, like multiplying a regular `number` with a `Complex` number or a `BigNumber`, and work with all of those in matrices. -Mathjs also allows to add a new data type, like say `BigInt`, with little effort. +Mathjs also allows to add a new data type with little effort. The solution that mathjs uses has two main ingredients: -- **Typed functions**. All functions are created using [`typed-function`](https://github.com/josdejong/typed-function/). This makes it easier to (dynamically) create and extend a single function with new data types, automatically do type conversions on function inputs, etc. So, if you create function multiply for two `number`s, you can extend it with support for multiplying two `BigInts`. If you define a conversion from `BigInt` to `number`, the typed-function will automatically allow you to multiply a `BigInt` with a `number`. +- **Typed functions**. All functions are created using [`typed-function`](https://github.com/josdejong/typed-function/). This makes it easier to (dynamically) create and extend a single function with new data types, automatically do type conversions on function inputs, etc. So, if you create function multiply for two `number`s, you can extend it with support for multiplying your own data type, say `MyDecimal`. If you define a conversion from `MyDecimal` to `number`, the typed-function will automatically allow you to multiply a `MyDecimal` with a `number`. -- **Dependency injection**. When we have a function `multiply` with support for `BigInt`, thanks to the dependency injection, other functions using `multiply` under the hood, like `prod`, will automatically support `BigInt` too. This also works the other way around: if you don't need the heavyweight `multiply` (which supports BigNumbers, matrices, etc), and you just need a plain and simple number support, you can use a lightweight implementation of `multiply` just for numbers, and inject that in `prod` and other functions. +- **Dependency injection**. When we have a function `multiply` with support for `MyDecimal`, thanks to the dependency injection, other functions using `multiply` under the hood, like `prod`, will automatically support `MyDecimal` too. This also works the other way around: if you don't need the heavyweight `multiply` (which supports BigNumbers, matrices, etc), and you just need a plain and simple number support, you can use a lightweight implementation of `multiply` just for numbers, and inject that in `prod` and other functions. At the lowest level, mathjs has immutable factory functions which create immutable functions. The core function `math.create(...)` creates a new instance having functions created from all passed factory functions. A mathjs instance is a collection of created functions. It contains a function like `math.import` to allow extending the instance with new functions, which can then be used in the expression parser. diff --git a/docs/core/configuration.md b/docs/core/configuration.md index 7c0424f08a..40a1bc7b7a 100644 --- a/docs/core/configuration.md +++ b/docs/core/configuration.md @@ -45,21 +45,29 @@ The following configuration options are available: determined by the option `matrix`. In case of mixed matrix inputs, a matrix will be returned always. -- `number`. The type of numeric output for functions which cannot - determine the numeric type from the inputs. For most functions though, - the type of output is determined from the the input: - a number as input will return a number as output, - a BigNumber as input returns a BigNumber as output. - - For example the functions `math.evaluate('2+3')`, `math.parse('2+3')`, - `math.range('1:10')`, and `math.unit('5cm')` use the `number` configuration - setting. But `math.sqrt(4)` will always return the number `2` - regardless of the `number` configuration, because the input is a number. - - Available values are: `'number'` (default), `'BigNumber'`, or `'Fraction'`. - [BigNumbers](../datatypes/bignumbers.js) have higher precision than the default - numbers of JavaScript, and [`Fractions`](../datatypes/fractions.js) store - values in terms of a numerator and denominator. +- `number`. The type used to parse strings into a numeric value or create a new + numeric value internally. + + For most functions, the type of output is determined from the input: + a number as input will return a number as output, a BigNumber as input + returns a BigNumber as output. But for example the functions + `math.evaluate('2+3')`, `math.parse('2+3')`, `math.range('1:10')`, + and `math.unit('5cm')` use the `number` configuration setting. + + Note that `math.sqrt(4)` will always return the number `2` regardless of + the `number` configuration, because the numeric type can be determined from + the input value. + + Available values are: `'number'` (default), `'BigNumber'`, `'bigint'`, or `'Fraction'`. + [BigNumbers](../datatypes/bignumbers.js) have higher precision than the default numbers of JavaScript, + [bigint](../datatypes/bigints.md) can represent large integer numbers, + and [`Fractions`](../datatypes/fractions.js) store values in terms of a numerator and + denominator. + +- `numberFallback`. When `number` is configured for example with value `'bigint'`, + and a value cannot be represented as `bigint` like in `math.evaluate('2.3')`, + the value will be parsed in the type configured with `numberFallback`. + Available values: `'number'` (default) or `'BigNumber'`. - `precision`. The maximum number of significant digits for BigNumbers. This setting only applies to BigNumbers, not to numbers. diff --git a/docs/datatypes/bigints.md b/docs/datatypes/bigints.md new file mode 100644 index 0000000000..4176e2296b --- /dev/null +++ b/docs/datatypes/bigints.md @@ -0,0 +1,54 @@ +# BigInts + +For calculations with large integer numbers, math.js supports the built-in `bigint` data type. + +## Usage + +A bigint can be created either by adding the suffix `n` to a `number`, using the `BigInt` constructor function, or using the util function `math.bigint`: + +```js +42n +BigInt('42') +math.bigint('42') +``` + +Most functions can determine the type of output from the type of input: +a `number` as input will return a `number` as output, a `bigint` as input returns +a `bigint` as output. Functions which cannot determine the type of output +from the input (for example `math.evaluate`) use the default number type `number`, +which can be configured when instantiating math.js. To configure the use of +`bigint` instead of [numbers](numbers.md) by default, configure math.js like: + +```js +math.config({ + number: 'bigint' +}) + +// use math +math.evaluate('70000000000000000123') // bigint 70000000000000000123n +``` + +## Support + +All basic arithmetic functions in math.js support `bigint`. Since `bigint` can only hold integer values, it is not applicable to for example trigonometric functions. When using a `bigint` in a function that does not support it, like `sqrt`, it will convert the `bigint` into a regular `number` and then execute the function: + +```js +math.sin(2n) // number 0.9092974268256817 +``` + +## Conversion + +There are utility functions to convert a `bigint` into a `number` or `BigNumber`: + +```js +// convert a number to bigint or BigNumber +math.bigint(42) // bigint, 42n +math.bignumber(42) // BigNumber, 42 + +// convert a bigint to a number or BigNumber +math.number(42n) // number, 42 +math.bignumber(42n) // BigNumber, 42 + +// losing digits when converting to number +math.number(70000000000000000123n) // number, 7000000000000000000 +``` diff --git a/docs/datatypes/index.md b/docs/datatypes/index.md index 5f3cd2e9ce..328422ed11 100644 --- a/docs/datatypes/index.md +++ b/docs/datatypes/index.md @@ -31,6 +31,9 @@ math.sqrt(4.41e2) // 21 // use BigNumbers math.add(math.bignumber(0.1), math.bignumber(0.2)) // BigNumber, 0.3 +// use bigint +math.add(300000000000000000n, 1n) // 300000000000000001n + // use Fractions math.add(math.fraction(1), math.fraction(3)) // Fraction, 0.(3) diff --git a/docs/datatypes/numbers.md b/docs/datatypes/numbers.md index 5d0372253a..f082d5cd6f 100644 --- a/docs/datatypes/numbers.md +++ b/docs/datatypes/numbers.md @@ -50,7 +50,7 @@ const ans = math.add(0.1, 0.2) // 0.30000000000000004 math.format(ans, {precision: 14}) // '0.3' ``` -Alternatives are to use [Fractions](fractions.md) which store a number as a numerator and denominator, or [BigNumbers](bignumbers.md), which store a number with a higher precision. +Alternatives are to use [Fractions](fractions.md) which store a number as a numerator and denominator, [BigNumbers](bignumbers.md) which store a number with a higher precision, or [bigint](bigints.md) which can store larger integer numbers. ## Minimum and maximum diff --git a/docs/index.md b/docs/index.md index f3e77f96e3..47e0340a56 100644 --- a/docs/index.md +++ b/docs/index.md @@ -26,6 +26,7 @@ Math.js can be used in the browser, in node.js and in any JavaScript engine. Ins - **[Data Types](datatypes/index.md)** - [Numbers](datatypes/numbers.md) - [BigNumbers](datatypes/bignumbers.md) + - [bigints](datatypes/bigints.md) - [Fractions](datatypes/fractions.md) - [Complex Numbers](datatypes/complex_numbers.md) - [Matrices](datatypes/matrices.md) diff --git a/examples/advanced/use_bigint.js b/examples/advanced/use_bigint.js deleted file mode 100644 index fe4f3a0c5e..0000000000 --- a/examples/advanced/use_bigint.js +++ /dev/null @@ -1,42 +0,0 @@ -// This example demonstrates how you could integrate support for BigInt -// in mathjs. It's just a proof of concept, for full support you will -// have to defined more functions and define conversions from and to -// other data types. -import { all, create, factory } from '../../lib/esm/index.js' -const math = create(all) - -// we can also add conversions here from number or string to BigInt -// and vice versa using math.typed.addConversion(...) - -math.import([ - factory('BigInt', ['typed'], function createBigInt ({ typed }) { - typed.addType({ - name: 'BigInt', - test: (x) => typeof x === 'bigint' // eslint-disable-line - }) - - return BigInt // eslint-disable-line - }, { lazy: false }), - - factory('bigint', ['typed', 'BigInt'], function createBigint ({ typed, BigInt }) { - return typed('bigint', { - 'number | string ': (x) => BigInt(x) // eslint-disable-line - }) - }), - - factory('add', ['typed'], function createBigIntAdd ({ typed }) { - return typed('add', { - 'BigInt, BigInt': (a, b) => a + b - }) - }), - - factory('pow', ['typed'], function createBigIntPow ({ typed }) { - return typed('pow', { - 'BigInt, BigInt': (a, b) => a ** b - }) - }) -]) - -console.log(math.evaluate('4349 + 5249')) -console.log(math.evaluate('bigint(4349) + bigint(5249)')) -console.log(math.evaluate('bigint(4349) ^ bigint(5249)')) diff --git a/package-lock.json b/package-lock.json index cebd724262..2f1fd7fb42 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4106,9 +4106,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001620", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001620.tgz", - "integrity": "sha512-WJvYsOjd1/BYUY6SNGUosK9DUidBPDTnOARHp3fSmFO1ekdxaY6nKRttEVrfMmYi80ctS0kz1wiWmm14fVc3ew==", + "version": "1.0.30001625", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001625.tgz", + "integrity": "sha512-4KE9N2gcRH+HQhpeiRZXd+1niLB/XNLAhSy4z7fI8EzcbcPoAqjNInxVHTiTwWfTIV4w096XG8OtCOCQQKPv3w==", "dev": true, "funding": [ { diff --git a/package.json b/package.json index 3cf884b7a1..21fe015fb6 100644 --- a/package.json +++ b/package.json @@ -162,6 +162,11 @@ "engines": { "node": ">= 18" }, + "browserslist": [ + "last 1 version", + "> 0.1%", + "not dead" + ], "bugs": { "url": "https://github.com/josdejong/mathjs/issues" }, diff --git a/src/core/config.js b/src/core/config.js index fa7f30e67d..005bba30f1 100644 --- a/src/core/config.js +++ b/src/core/config.js @@ -10,9 +10,13 @@ export const DEFAULT_CONFIG = { // type of default matrix output. Choose 'matrix' (default) or 'array' matrix: 'Matrix', - // type of default number output. Choose 'number' (default) 'BigNumber', or 'Fraction + // type of default number output. Choose 'number' (default) 'BigNumber', 'bigint', or 'Fraction' number: 'number', + // type of fallback used for config { number: 'bigint' } when a value cannot be represented + // in the configured numeric type. Choose 'number' (default) or 'BigNumber'. + numberFallback: 'number', + // number of significant digits in BigNumbers precision: 64, diff --git a/src/core/create.js b/src/core/create.js index 053f56ad21..d7effce942 100644 --- a/src/core/create.js +++ b/src/core/create.js @@ -43,7 +43,8 @@ import { isString, isSymbolNode, isUndefined, - isUnit + isUnit, + isBigInt } from '../utils/is.js' import { ArgumentsError } from '../error/ArgumentsError.js' import { DimensionError } from '../error/DimensionError.js' @@ -107,6 +108,7 @@ export function create (factories, config) { isNumber, isComplex, isBigNumber, + isBigInt, isFraction, isUnit, isString, diff --git a/src/core/function/config.js b/src/core/function/config.js index 5bed7de372..9a5d68ea55 100644 --- a/src/core/function/config.js +++ b/src/core/function/config.js @@ -38,7 +38,7 @@ export function configFactory (config, emit) { * {string} matrix * A string 'Matrix' (default) or 'Array'. * {string} number - * A string 'number' (default), 'BigNumber', or 'Fraction' + * A string 'number' (default), 'BigNumber', 'bigint', or 'Fraction' * {number} precision * The number of significant digits for BigNumbers. * Not applicable for Numbers. diff --git a/src/core/function/typed.js b/src/core/function/typed.js index 8de1b761dd..9dce87da65 100644 --- a/src/core/function/typed.js +++ b/src/core/function/typed.js @@ -75,7 +75,7 @@ import { isString, isSymbolNode, isUndefined, - isUnit + isUnit, isBigInt } from '../../utils/is.js' import typedFunction from 'typed-function' import { digits } from '../../utils/number.js' @@ -116,6 +116,7 @@ export const createTyped = /* #__PURE__ */ factory('typed', dependencies, functi { name: 'number', test: isNumber }, { name: 'Complex', test: isComplex }, { name: 'BigNumber', test: isBigNumber }, + { name: 'bigint', test: isBigInt }, { name: 'Fraction', test: isFraction }, { name: 'Unit', test: isUnit }, // The following type matches a valid variable name, i.e., an alphanumeric @@ -201,6 +202,37 @@ export const createTyped = /* #__PURE__ */ factory('typed', dependencies, functi return new Complex(x.toNumber(), 0) } + }, { + from: 'bigint', + to: 'number', + convert: function (x) { + if (x > Number.MAX_SAFE_INTEGER) { + throw new TypeError('Cannot implicitly convert bigint to number: ' + + 'value exceeds the max safe integer value (value: ' + x + ')') + } + + return Number(x) + } + }, { + from: 'bigint', + to: 'BigNumber', + convert: function (x) { + if (!BigNumber) { + throwNoBignumber(x) + } + + return new BigNumber(x.toString()) + } + }, { + from: 'bigint', + to: 'Fraction', + convert: function (x) { + if (!Fraction) { + throwNoFraction(x) + } + + return new Fraction(x.toString()) + } }, { from: 'Fraction', to: 'BigNumber', @@ -265,6 +297,16 @@ export const createTyped = /* #__PURE__ */ factory('typed', dependencies, functi throw new Error('Cannot convert "' + x + '" to BigNumber') } } + }, { + from: 'string', + to: 'bigint', + convert: function (x) { + try { + return BigInt(x) + } catch (err) { + throw new Error('Cannot convert "' + x + '" to BigInt') + } + } }, { from: 'string', to: 'Fraction', @@ -309,6 +351,12 @@ export const createTyped = /* #__PURE__ */ factory('typed', dependencies, functi return new BigNumber(+x) } + }, { + from: 'boolean', + to: 'bigint', + convert: function (x) { + return BigInt(+x) + } }, { from: 'boolean', to: 'Fraction', diff --git a/src/entry/typeChecks.js b/src/entry/typeChecks.js index e187dc3745..0ccdb83dc0 100644 --- a/src/entry/typeChecks.js +++ b/src/entry/typeChecks.js @@ -5,6 +5,7 @@ export { isArrayNode, isAssignmentNode, isBigNumber, + isBigInt, isBlockNode, isBoolean, isChain, diff --git a/src/expression/embeddedDocs/construction/bigint.js b/src/expression/embeddedDocs/construction/bigint.js new file mode 100644 index 0000000000..7f71babd54 --- /dev/null +++ b/src/expression/embeddedDocs/construction/bigint.js @@ -0,0 +1,17 @@ +export const bigintDocs = { + name: 'bigint', + category: 'Construction', + syntax: [ + 'bigint(x)' + ], + description: + 'Create a bigint, an integer with an arbitrary number of digits, from a number or string.', + examples: [ + '123123123123123123 # a large number will lose digits', + 'bigint("123123123123123123")', + 'bignumber(["1", "3", "5"])' + ], + seealso: [ + 'boolean', 'bignumber', 'number', 'complex', 'fraction', 'index', 'matrix', 'string', 'unit' + ] +} diff --git a/src/expression/embeddedDocs/construction/bignumber.js b/src/expression/embeddedDocs/construction/bignumber.js index 8c5e52305f..b603573a63 100644 --- a/src/expression/embeddedDocs/construction/bignumber.js +++ b/src/expression/embeddedDocs/construction/bignumber.js @@ -14,6 +14,6 @@ export const bignumberDocs = { 'bignumber([0.1, 0.2, 0.3])' ], seealso: [ - 'boolean', 'complex', 'fraction', 'index', 'matrix', 'string', 'unit' + 'boolean', 'bigint', 'complex', 'fraction', 'index', 'matrix', 'string', 'unit' ] } diff --git a/src/expression/embeddedDocs/construction/number.js b/src/expression/embeddedDocs/construction/number.js index b873bc66af..5dee36fbd2 100644 --- a/src/expression/embeddedDocs/construction/number.js +++ b/src/expression/embeddedDocs/construction/number.js @@ -19,6 +19,6 @@ export const numberDocs = { 'number(unit("52cm"), "m")' ], seealso: [ - 'bignumber', 'boolean', 'complex', 'fraction', 'index', 'matrix', 'string', 'unit' + 'bignumber', 'bigint', 'boolean', 'complex', 'fraction', 'index', 'matrix', 'string', 'unit' ] } diff --git a/src/expression/embeddedDocs/embeddedDocs.js b/src/expression/embeddedDocs/embeddedDocs.js index 9dd8a4e527..8474694ed8 100644 --- a/src/expression/embeddedDocs/embeddedDocs.js +++ b/src/expression/embeddedDocs/embeddedDocs.js @@ -16,6 +16,7 @@ import { tauDocs } from './constants/tau.js' import { trueDocs } from './constants/true.js' import { versionDocs } from './constants/version.js' import { bignumberDocs } from './construction/bignumber.js' +import { bigintDocs } from './construction/bigint.js' import { booleanDocs } from './construction/boolean.js' import { complexDocs } from './construction/complex.js' import { createUnitDocs } from './construction/createUnit.js' @@ -246,6 +247,7 @@ export const embeddedDocs = { // construction functions bignumber: bignumberDocs, + bigint: bigintDocs, boolean: booleanDocs, complex: complexDocs, createUnit: createUnitDocs, diff --git a/src/expression/embeddedDocs/function/utils/numeric.js b/src/expression/embeddedDocs/function/utils/numeric.js index 3b4c9d1679..4d7475f1ab 100644 --- a/src/expression/embeddedDocs/function/utils/numeric.js +++ b/src/expression/embeddedDocs/function/utils/numeric.js @@ -4,14 +4,15 @@ export const numericDocs = { syntax: [ 'numeric(x)' ], - description: 'Convert a numeric input to a specific numeric type: number, BigNumber, or Fraction.', + description: 'Convert a numeric input to a specific numeric type: number, BigNumber, bigint, or Fraction.', examples: [ 'numeric("4")', 'numeric("4", "number")', + 'numeric("4", "bigint")', 'numeric("4", "BigNumber")', 'numeric("4", "Fraction")', 'numeric(4, "Fraction")', 'numeric(fraction(2, 5), "number")' ], - seealso: ['number', 'fraction', 'bignumber', 'string', 'format'] + seealso: ['number', 'bigint', 'fraction', 'bignumber', 'string', 'format'] } diff --git a/src/expression/node/ConstantNode.js b/src/expression/node/ConstantNode.js index 6c3a95dab8..7ab4443a22 100644 --- a/src/expression/node/ConstantNode.js +++ b/src/expression/node/ConstantNode.js @@ -18,7 +18,7 @@ export const createConstantNode = /* #__PURE__ */ factory(name, dependencies, ({ * new ConstantNode(2.3) * new ConstantNode('hello') * - * @param {*} value Value can be any type (number, BigNumber, string, ...) + * @param {*} value Value can be any type (number, BigNumber, bigint, string, ...) * @constructor ConstantNode * @extends {Node} */ @@ -97,6 +97,7 @@ export const createConstantNode = /* #__PURE__ */ factory(name, dependencies, ({ switch (typeOf(this.value)) { case 'number': + case 'bigint': case 'BigNumber': case 'Fraction': return '' + value + '' @@ -164,6 +165,10 @@ export const createConstantNode = /* #__PURE__ */ factory(name, dependencies, ({ return value } + case 'bigint': { + return value.toString() + } + case 'Fraction': return this.value.toLatex() diff --git a/src/expression/parse.js b/src/expression/parse.js index 7961e0ba0c..54a7d17f20 100644 --- a/src/expression/parse.js +++ b/src/expression/parse.js @@ -1,6 +1,7 @@ import { factory } from '../utils/factory.js' import { isAccessorNode, isConstantNode, isFunctionNode, isOperatorNode, isSymbolNode, rule2Node } from '../utils/is.js' import { deepMap } from '../utils/collection.js' +import { safeNumberType } from '../utils/number.js' import { hasOwnProperty } from '../utils/object.js' const name = 'parse' @@ -1678,7 +1679,10 @@ export const createParse = /* #__PURE__ */ factory(name, dependencies, ({ numberStr = state.token getToken(state) - return new ConstantNode(numeric(numberStr, config.number)) + const numericType = safeNumberType(numberStr, config) + const value = numeric(numberStr, numericType) + + return new ConstantNode(value) } return parseParentheses(state) diff --git a/src/factoriesAny.js b/src/factoriesAny.js index e9ae77caa1..69d27b9bb3 100644 --- a/src/factoriesAny.js +++ b/src/factoriesAny.js @@ -18,6 +18,7 @@ export { createTypeOf } from './function/utils/typeOf.js' export { createEqualScalar } from './function/relational/equalScalar.js' export { createSparseMatrixClass } from './type/matrix/SparseMatrix.js' export { createNumber } from './type/number.js' +export { createBigint } from './type/bigint.js' export { createString } from './type/string.js' export { createBoolean } from './type/boolean.js' export { createBignumber } from './type/bignumber/function/bignumber.js' diff --git a/src/factoriesNumber.js b/src/factoriesNumber.js index 3d2ee31ef8..b0183d2122 100644 --- a/src/factoriesNumber.js +++ b/src/factoriesNumber.js @@ -175,6 +175,7 @@ export { // create export { createNumber } from './type/number.js' +export { createBigint } from './type/bigint.js' export { createString } from './type/string.js' export { createBoolean } from './type/boolean.js' export { createParser } from './expression/function/parser.js' diff --git a/src/function/algebra/derivative.js b/src/function/algebra/derivative.js index 078ed03880..93e19330bb 100644 --- a/src/function/algebra/derivative.js +++ b/src/function/algebra/derivative.js @@ -1,5 +1,6 @@ import { isConstantNode, typeOf } from '../../utils/is.js' import { factory } from '../../utils/factory.js' +import { safeNumberType } from '../../utils/number.js' const name = 'derivative' const dependencies = [ @@ -754,7 +755,7 @@ export const createDerivative = /* #__PURE__ */ factory(name, dependencies, ({ * @return {ConstantNode} */ function createConstantNode (value, valueType) { - return new ConstantNode(numeric(value, valueType || config.number)) + return new ConstantNode(numeric(value, valueType || safeNumberType(String(value), config))) } return derivative diff --git a/src/function/algebra/simplifyConstant.js b/src/function/algebra/simplifyConstant.js index f408bcd989..1820f3caaf 100644 --- a/src/function/algebra/simplifyConstant.js +++ b/src/function/algebra/simplifyConstant.js @@ -1,5 +1,6 @@ import { isFraction, isMatrix, isNode, isArrayNode, isConstantNode, isIndexNode, isObjectNode, isOperatorNode } from '../../utils/is.js' import { factory } from '../../utils/factory.js' +import { safeNumberType } from '../../utils/number.js' import { createUtil } from './simplify/util.js' import { noBignumber, noFraction } from '../../utils/noop.js' @@ -112,6 +113,12 @@ export const createSimplifyConstant = /* #__PURE__ */ factory(name, dependencies } return new ConstantNode(n) // old parameters: (n.toString(), 'number') }, + bigint: function (n) { + if (n < 0n) { + return unaryMinusNode(new ConstantNode(-n)) + } + return new ConstantNode(n) + }, Complex: function (s) { throw new Error('Cannot convert Complex number to Node') }, @@ -151,12 +158,16 @@ export const createSimplifyConstant = /* #__PURE__ */ factory(name, dependencies // BigNumbers are left alone const _toNumber = typed({ 'string, Object': function (s, options) { - if (config.number === 'BigNumber') { + const numericType = safeNumberType(s, config) + + if (numericType === 'BigNumber') { if (bignumber === undefined) { noBignumber() } return bignumber(s) - } else if (config.number === 'Fraction') { + } else if (numericType === 'bigint') { + return BigInt(s) + } else if (numericType === 'Fraction') { if (fraction === undefined) { noFraction() } @@ -175,6 +186,10 @@ export const createSimplifyConstant = /* #__PURE__ */ factory(name, dependencies return _exactFraction(s, options) }, + 'bigint, Object': function (s, options) { + return s + }, + 'Complex, Object': function (s, options) { if (s.im !== 0) { return s @@ -343,6 +358,7 @@ export const createSimplifyConstant = /* #__PURE__ */ factory(name, dependencies case 'ConstantNode': switch (typeof node.value) { case 'number': return _toNumber(node.value, options) + case 'bigint': return _toNumber(node.value, options) case 'string': return node.value default: if (!isNaN(node.value)) return _toNumber(node.value, options) diff --git a/src/function/arithmetic/abs.js b/src/function/arithmetic/abs.js index a300f315b8..06bef08852 100644 --- a/src/function/arithmetic/abs.js +++ b/src/function/arithmetic/abs.js @@ -25,9 +25,9 @@ export const createAbs = /* #__PURE__ */ factory(name, dependencies, ({ typed }) * * sign * - * @param {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} x + * @param {number | BigNumber | bigint | Fraction | Complex | Array | Matrix | Unit} x * A number or matrix for which to get the absolute value - * @return {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} + * @return {number | BigNumber | bigint | Fraction | Complex | Array | Matrix | Unit} * Absolute value of `x` */ return typed(name, { @@ -35,6 +35,8 @@ export const createAbs = /* #__PURE__ */ factory(name, dependencies, ({ typed }) 'Complex | BigNumber | Fraction | Unit': x => x.abs(), + bigint: x => x < 0n ? -x : x, + // deep map collection, skip zeros since abs(0) = 0 'Array | Matrix': typed.referToSelf(self => x => deepMap(x, self, true)) }) diff --git a/src/function/arithmetic/add.js b/src/function/arithmetic/add.js index 5afbc601b3..424398610b 100644 --- a/src/function/arithmetic/add.js +++ b/src/function/arithmetic/add.js @@ -53,9 +53,9 @@ export const createAdd = /* #__PURE__ */ factory( * * subtract, sum * - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x First value to add - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y Second value to add - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Sum of `x` and `y` + * @param {number | BigNumber | bigint | Fraction | Complex | Unit | Array | Matrix} x First value to add + * @param {number | BigNumber | bigint | Fraction | Complex | Unit | Array | Matrix} y Second value to add + * @return {number | BigNumber | bigint | Fraction | Complex | Unit | Array | Matrix} Sum of `x` and `y` */ return typed( name, diff --git a/src/function/arithmetic/addScalar.js b/src/function/arithmetic/addScalar.js index 3a40ce079f..b846d1c8f1 100644 --- a/src/function/arithmetic/addScalar.js +++ b/src/function/arithmetic/addScalar.js @@ -12,9 +12,9 @@ export const createAddScalar = /* #__PURE__ */ factory(name, dependencies, ({ ty * * This function does not support collections (Array or Matrix). * - * @param {number | BigNumber | Fraction | Complex | Unit} x First value to add - * @param {number | BigNumber | Fraction | Complex} y Second value to add - * @return {number | BigNumber | Fraction | Complex | Unit} Sum of `x` and `y` + * @param {number | BigNumber | bigint | Fraction | Complex | Unit} x First value to add + * @param {number | BigNumber | bigint | Fraction | Complex} y Second value to add + * @return {number | BigNumber | bigint | Fraction | Complex | Unit} Sum of `x` and `y` * @private */ return typed(name, { @@ -29,6 +29,10 @@ export const createAddScalar = /* #__PURE__ */ factory(name, dependencies, ({ ty return x.plus(y) }, + 'bigint, bigint': function (x, y) { + return x + y + }, + 'Fraction, Fraction': function (x, y) { return x.add(y) }, diff --git a/src/function/arithmetic/cube.js b/src/function/arithmetic/cube.js index 87ddbe1c98..c8eea4609c 100644 --- a/src/function/arithmetic/cube.js +++ b/src/function/arithmetic/cube.js @@ -27,8 +27,8 @@ export const createCube = /* #__PURE__ */ factory(name, dependencies, ({ typed } * * multiply, square, pow, cbrt * - * @param {number | BigNumber | Fraction | Complex | Unit} x Number for which to calculate the cube - * @return {number | BigNumber | Fraction | Complex | Unit} Cube of x + * @param {number | BigNumber | bigint | Fraction | Complex | Unit} x Number for which to calculate the cube + * @return {number | BigNumber | bigint | Fraction | Complex | Unit} Cube of x */ return typed(name, { number: cubeNumber, @@ -41,6 +41,10 @@ export const createCube = /* #__PURE__ */ factory(name, dependencies, ({ typed } return x.times(x).times(x) }, + bigint: function (x) { + return x * x * x + }, + Fraction: function (x) { return x.pow(3) // Is faster than mul()mul()mul() }, diff --git a/src/function/arithmetic/divide.js b/src/function/arithmetic/divide.js index 9e5eea3bb9..84840b7f0f 100644 --- a/src/function/arithmetic/divide.js +++ b/src/function/arithmetic/divide.js @@ -44,9 +44,9 @@ export const createDivide = /* #__PURE__ */ factory(name, dependencies, ({ typed * * multiply * - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x Numerator - * @param {number | BigNumber | Fraction | Complex | Array | Matrix} y Denominator - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Quotient, `x / y` + * @param {number | BigNumber | bigint | Fraction | Complex | Unit | Array | Matrix} x Numerator + * @param {number | BigNumber | bigint | Fraction | Complex | Array | Matrix} y Denominator + * @return {number | BigNumber | bigint | Fraction | Complex | Unit | Array | Matrix} Quotient, `x / y` */ return typed('divide', extend({ // we extend the signatures of divideScalar with signatures dealing with matrices diff --git a/src/function/arithmetic/divideScalar.js b/src/function/arithmetic/divideScalar.js index e5d6194740..ac1077c655 100644 --- a/src/function/arithmetic/divideScalar.js +++ b/src/function/arithmetic/divideScalar.js @@ -11,9 +11,9 @@ export const createDivideScalar = /* #__PURE__ */ factory(name, dependencies, ({ * * This function does not support collections (Array or Matrix). * - * @param {number | BigNumber | Fraction | Complex | Unit} x Numerator - * @param {number | BigNumber | Fraction | Complex} y Denominator - * @return {number | BigNumber | Fraction | Complex | Unit} Quotient, `x / y` + * @param {number | BigNumber | bigint | Fraction | Complex | Unit} x Numerator + * @param {number | BigNumber | bigint | Fraction | Complex} y Denominator + * @return {number | BigNumber | bigint | Fraction | Complex | Unit} Quotient, `x / y` * @private */ return typed(name, { @@ -29,6 +29,10 @@ export const createDivideScalar = /* #__PURE__ */ factory(name, dependencies, ({ return x.div(y) }, + 'bigint, bigint': function (x, y) { + return x / y + }, + 'Fraction, Fraction': function (x, y) { return x.div(y) }, diff --git a/src/function/arithmetic/mod.js b/src/function/arithmetic/mod.js index 19a3ac80d6..dee0b97e4a 100644 --- a/src/function/arithmetic/mod.js +++ b/src/function/arithmetic/mod.js @@ -59,9 +59,9 @@ export const createMod = /* #__PURE__ */ factory(name, dependencies, ({ typed, c * * divide * - * @param {number | BigNumber | Fraction | Array | Matrix} x Dividend - * @param {number | BigNumber | Fraction | Array | Matrix} y Divisor - * @return {number | BigNumber | Fraction | Array | Matrix} Returns the remainder of `x` divided by `y`. + * @param {number | BigNumber | bigint | Fraction | Array | Matrix} x Dividend + * @param {number | BigNumber | bigint | Fraction | Array | Matrix} y Divisor + * @return {number | BigNumber | bigint | Fraction | Array | Matrix} Returns the remainder of `x` divided by `y`. */ return typed( name, @@ -72,6 +72,19 @@ export const createMod = /* #__PURE__ */ factory(name, dependencies, ({ typed, c return y.isZero() ? x : x.sub(y.mul(floor(x.div(y)))) }, + 'bigint, bigint': function (x, y) { + if (y === 0n) { + return x + } + + if (x < 0) { + const m = x % y + return m === 0n ? m : m + y + } + + return x % y + }, + 'Fraction, Fraction': function (x, y) { return y.equals(0) ? x : x.sub(y.mul(floor(x.div(y)))) } diff --git a/src/function/arithmetic/multiply.js b/src/function/arithmetic/multiply.js index 19bd3b7eef..07e1553b83 100644 --- a/src/function/arithmetic/multiply.js +++ b/src/function/arithmetic/multiply.js @@ -789,9 +789,9 @@ export const createMultiply = /* #__PURE__ */ factory(name, dependencies, ({ typ * * divide, prod, cross, dot * - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x First value to multiply - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y Second value to multiply - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Multiplication of `x` and `y` + * @param {number | BigNumber | bigint | Fraction | Complex | Unit | Array | Matrix} x First value to multiply + * @param {number | BigNumber | bigint | Fraction | Complex | Unit | Array | Matrix} y Second value to multiply + * @return {number | BigNumber | bigint | Fraction | Complex | Unit | Array | Matrix} Multiplication of `x` and `y` */ return typed(name, multiplyScalar, { // we extend the signatures of multiplyScalar with signatures dealing with matrices diff --git a/src/function/arithmetic/multiplyScalar.js b/src/function/arithmetic/multiplyScalar.js index 61555555d0..37ada2d779 100644 --- a/src/function/arithmetic/multiplyScalar.js +++ b/src/function/arithmetic/multiplyScalar.js @@ -12,9 +12,9 @@ export const createMultiplyScalar = /* #__PURE__ */ factory(name, dependencies, * * This function does not support collections (Array or Matrix). * - * @param {number | BigNumber | Fraction | Complex | Unit} x First value to multiply - * @param {number | BigNumber | Fraction | Complex} y Second value to multiply - * @return {number | BigNumber | Fraction | Complex | Unit} Multiplication of `x` and `y` + * @param {number | BigNumber | bigint | Fraction | Complex | Unit} x First value to multiply + * @param {number | BigNumber | bigint | Fraction | Complex} y Second value to multiply + * @return {number | BigNumber | bigint | Fraction | Complex | Unit} Multiplication of `x` and `y` * @private */ return typed('multiplyScalar', { @@ -29,6 +29,10 @@ export const createMultiplyScalar = /* #__PURE__ */ factory(name, dependencies, return x.times(y) }, + 'bigint, bigint': function (x, y) { + return x * y + }, + 'Fraction, Fraction': function (x, y) { return x.mul(y) }, diff --git a/src/function/arithmetic/pow.js b/src/function/arithmetic/pow.js index 891aa3b5f3..d68deb545c 100644 --- a/src/function/arithmetic/pow.js +++ b/src/function/arithmetic/pow.js @@ -51,9 +51,9 @@ export const createPow = /* #__PURE__ */ factory(name, dependencies, ({ typed, c * * multiply, sqrt, cbrt, nthRoot * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x The base - * @param {number | BigNumber | Complex} y The exponent - * @return {number | BigNumber | Complex | Array | Matrix} The value of `x` to the power `y` + * @param {number | BigNumber | bigint | Complex | Unit | Array | Matrix} x The base + * @param {number | BigNumber | bigint | Complex} y The exponent + * @return {number | BigNumber | bigint | Complex | Array | Matrix} The value of `x` to the power `y` */ return typed(name, { 'number, number': _pow, @@ -70,6 +70,8 @@ export const createPow = /* #__PURE__ */ factory(name, dependencies, ({ typed, c } }, + 'bigint, bigint': (x, y) => x ** y, + 'Fraction, Fraction': function (x, y) { const result = x.pow(y) diff --git a/src/function/arithmetic/sign.js b/src/function/arithmetic/sign.js index dec523ac75..56a728b04e 100644 --- a/src/function/arithmetic/sign.js +++ b/src/function/arithmetic/sign.js @@ -31,9 +31,9 @@ export const createSign = /* #__PURE__ */ factory(name, dependencies, ({ typed, * * abs * - * @param {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} x + * @param {number | BigNumber | bigint | Fraction | Complex | Array | Matrix | Unit} x * The number for which to determine the sign - * @return {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} + * @return {number | BigNumber | bigint | Fraction | Complex | Array | Matrix | Unit} * The sign of `x` */ return typed(name, { @@ -47,6 +47,10 @@ export const createSign = /* #__PURE__ */ factory(name, dependencies, ({ typed, return new BigNumber(x.cmp(0)) }, + bigint: function (x) { + return x > 0n ? 1n : x < 0n ? -1n : 0n + }, + Fraction: function (x) { return new Fraction(x.s, 1) }, diff --git a/src/function/arithmetic/square.js b/src/function/arithmetic/square.js index 5162f7fac6..056411b0b4 100644 --- a/src/function/arithmetic/square.js +++ b/src/function/arithmetic/square.js @@ -28,9 +28,9 @@ export const createSquare = /* #__PURE__ */ factory(name, dependencies, ({ typed * * multiply, cube, sqrt, pow * - * @param {number | BigNumber | Fraction | Complex | Unit} x + * @param {number | BigNumber | bigint | Fraction | Complex | Unit} x * Number for which to calculate the square - * @return {number | BigNumber | Fraction | Complex | Unit} + * @return {number | BigNumber | bigint | Fraction | Complex | Unit} * Squared value */ return typed(name, { @@ -44,6 +44,10 @@ export const createSquare = /* #__PURE__ */ factory(name, dependencies, ({ typed return x.times(x) }, + bigint: function (x) { + return x * x + }, + Fraction: function (x) { return x.mul(x) }, diff --git a/src/function/arithmetic/subtract.js b/src/function/arithmetic/subtract.js index 4c7057888d..aa6732484b 100644 --- a/src/function/arithmetic/subtract.js +++ b/src/function/arithmetic/subtract.js @@ -53,9 +53,9 @@ export const createSubtract = /* #__PURE__ */ factory(name, dependencies, ({ typ * * add * - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x Initial value - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y Value to subtract from `x` - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Subtraction of `x` and `y` + * @param {number | BigNumber | bigint | Fraction | Complex | Unit | Array | Matrix} x Initial value + * @param {number | BigNumber | bigint | Fraction | Complex | Unit | Array | Matrix} y Value to subtract from `x` + * @return {number | BigNumber | bigint | Fraction | Complex | Unit | Array | Matrix} Subtraction of `x` and `y` */ return typed( name, diff --git a/src/function/arithmetic/subtractScalar.js b/src/function/arithmetic/subtractScalar.js index ab54a5e3af..075f5300b9 100644 --- a/src/function/arithmetic/subtractScalar.js +++ b/src/function/arithmetic/subtractScalar.js @@ -12,9 +12,9 @@ export const createSubtractScalar = /* #__PURE__ */ factory(name, dependencies, * * This function does not support collections (Array or Matrix). * - * @param {number | BigNumber | Fraction | Complex | Unit} x First value - * @param {number | BigNumber | Fraction | Complex} y Second value to be subtracted from `x` - * @return {number | BigNumber | Fraction | Complex | Unit} Difference of `x` and `y` + * @param {number | BigNumber | bigint | Fraction | Complex | Unit} x First value + * @param {number | BigNumber | bigint | Fraction | Complex} y Second value to be subtracted from `x` + * @return {number | BigNumber | bigint | Fraction | Complex | Unit} Difference of `x` and `y` * @private */ return typed(name, { @@ -29,6 +29,10 @@ export const createSubtractScalar = /* #__PURE__ */ factory(name, dependencies, return x.minus(y) }, + 'bigint, bigint': function (x, y) { + return x - y + }, + 'Fraction, Fraction': function (x, y) { return x.sub(y) }, diff --git a/src/function/arithmetic/unaryMinus.js b/src/function/arithmetic/unaryMinus.js index 32da37c240..98148de0bd 100644 --- a/src/function/arithmetic/unaryMinus.js +++ b/src/function/arithmetic/unaryMinus.js @@ -26,14 +26,16 @@ export const createUnaryMinus = /* #__PURE__ */ factory(name, dependencies, ({ t * * add, subtract, unaryPlus * - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x Number to be inverted. - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Returns the value with inverted sign. + * @param {number | BigNumber | bigint | Fraction | Complex | Unit | Array | Matrix} x Number to be inverted. + * @return {number | BigNumber | bigint | Fraction | Complex | Unit | Array | Matrix} Returns the value with inverted sign. */ return typed(name, { number: unaryMinusNumber, 'Complex | BigNumber | Fraction': x => x.neg(), + bigint: x => -x, + Unit: typed.referToSelf(self => x => { const res = x.clone() res.value = typed.find(self, res.valueType())(x.value) diff --git a/src/function/arithmetic/unaryPlus.js b/src/function/arithmetic/unaryPlus.js index 805eda1fe3..a6b2ccf9ce 100644 --- a/src/function/arithmetic/unaryPlus.js +++ b/src/function/arithmetic/unaryPlus.js @@ -1,11 +1,12 @@ import { factory } from '../../utils/factory.js' import { deepMap } from '../../utils/collection.js' import { unaryPlusNumber } from '../../plain/number/index.js' +import { safeNumberType } from '../../utils/number.js' const name = 'unaryPlus' -const dependencies = ['typed', 'config', 'BigNumber'] +const dependencies = ['typed', 'config', 'numeric'] -export const createUnaryPlus = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, BigNumber }) => { +export const createUnaryPlus = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, numeric }) => { /** * Unary plus operation. * Boolean values and strings will be converted to a number, numeric values will be returned as is. @@ -25,9 +26,9 @@ export const createUnaryPlus = /* #__PURE__ */ factory(name, dependencies, ({ ty * * unaryMinus, add, subtract * - * @param {number | BigNumber | Fraction | string | Complex | Unit | Array | Matrix} x + * @param {number | BigNumber | bigint | Fraction | string | Complex | Unit | Array | Matrix} x * Input value - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} + * @return {number | BigNumber | bigint | Fraction | Complex | Unit | Array | Matrix} * Returns the input value when numeric, converts to a number when input is non-numeric. */ return typed(name, { @@ -41,6 +42,10 @@ export const createUnaryPlus = /* #__PURE__ */ factory(name, dependencies, ({ ty return x // bignumbers are immutable }, + bigint: function (x) { + return x + }, + Fraction: function (x) { return x // fractions are immutable }, @@ -52,9 +57,12 @@ export const createUnaryPlus = /* #__PURE__ */ factory(name, dependencies, ({ ty // deep map collection, skip zeros since unaryPlus(0) = 0 'Array | Matrix': typed.referToSelf(self => x => deepMap(x, self, true)), - 'boolean | string': function (x) { - // convert to a number or bignumber - return (config.number === 'BigNumber') ? new BigNumber(+x) : +x + boolean: function (x) { + return numeric(x ? 1 : 0, config.number) + }, + + string: function (x) { + return numeric(x, safeNumberType(x, config)) } }) }) diff --git a/src/function/bitwise/bitAnd.js b/src/function/bitwise/bitAnd.js index 621af4c942..d6e169b09e 100644 --- a/src/function/bitwise/bitAnd.js +++ b/src/function/bitwise/bitAnd.js @@ -38,15 +38,16 @@ export const createBitAnd = /* #__PURE__ */ factory(name, dependencies, ({ typed * * bitNot, bitOr, bitXor, leftShift, rightArithShift, rightLogShift * - * @param {number | BigNumber | Array | Matrix} x First value to and - * @param {number | BigNumber | Array | Matrix} y Second value to and - * @return {number | BigNumber | Array | Matrix} AND of `x` and `y` + * @param {number | BigNumber | bigint | Array | Matrix} x First value to and + * @param {number | BigNumber | bigint | Array | Matrix} y Second value to and + * @return {number | BigNumber | bigint | Array | Matrix} AND of `x` and `y` */ return typed( name, { 'number, number': bitAndNumber, - 'BigNumber, BigNumber': bitAndBigNumber + 'BigNumber, BigNumber': bitAndBigNumber, + 'bigint, bigint': (x, y) => x & y }, matrixAlgorithmSuite({ SS: matAlgo06xS0S0, diff --git a/src/function/bitwise/bitNot.js b/src/function/bitwise/bitNot.js index 388aeab41d..7823834127 100644 --- a/src/function/bitwise/bitNot.js +++ b/src/function/bitwise/bitNot.js @@ -26,12 +26,13 @@ export const createBitNot = /* #__PURE__ */ factory(name, dependencies, ({ typed * * bitAnd, bitOr, bitXor, leftShift, rightArithShift, rightLogShift * - * @param {number | BigNumber | Array | Matrix} x Value to not - * @return {number | BigNumber | Array | Matrix} NOT of `x` + * @param {number | BigNumber | bigint | Array | Matrix} x Value to not + * @return {number | BigNumber | bigint | Array | Matrix} NOT of `x` */ return typed(name, { number: bitNotNumber, BigNumber: bitNotBigNumber, + bigint: x => ~x, 'Array | Matrix': typed.referToSelf(self => x => deepMap(x, self)) }) }) diff --git a/src/function/bitwise/bitOr.js b/src/function/bitwise/bitOr.js index 5f24394c24..c0f7dea215 100644 --- a/src/function/bitwise/bitOr.js +++ b/src/function/bitwise/bitOr.js @@ -40,15 +40,16 @@ export const createBitOr = /* #__PURE__ */ factory(name, dependencies, ({ typed, * * bitAnd, bitNot, bitXor, leftShift, rightArithShift, rightLogShift * - * @param {number | BigNumber | Array | Matrix} x First value to or - * @param {number | BigNumber | Array | Matrix} y Second value to or - * @return {number | BigNumber | Array | Matrix} OR of `x` and `y` + * @param {number | BigNumber | bigint | Array | Matrix} x First value to or + * @param {number | BigNumber | bigint | Array | Matrix} y Second value to or + * @return {number | BigNumber | bigint | Array | Matrix} OR of `x` and `y` */ return typed( name, { 'number, number': bitOrNumber, - 'BigNumber, BigNumber': bitOrBigNumber + 'BigNumber, BigNumber': bitOrBigNumber, + 'bigint, bigint': (x, y) => x | y }, matrixAlgorithmSuite({ SS: matAlgo04xSidSid, diff --git a/src/function/bitwise/bitXor.js b/src/function/bitwise/bitXor.js index 7568860493..bec33105cb 100644 --- a/src/function/bitwise/bitXor.js +++ b/src/function/bitwise/bitXor.js @@ -38,15 +38,16 @@ export const createBitXor = /* #__PURE__ */ factory(name, dependencies, ({ typed * * bitAnd, bitNot, bitOr, leftShift, rightArithShift, rightLogShift * - * @param {number | BigNumber | Array | Matrix} x First value to xor - * @param {number | BigNumber | Array | Matrix} y Second value to xor - * @return {number | BigNumber | Array | Matrix} XOR of `x` and `y` + * @param {number | BigNumber | bigint | Array | Matrix} x First value to xor + * @param {number | BigNumber | bigint | Array | Matrix} y Second value to xor + * @return {number | BigNumber | bigint | Array | Matrix} XOR of `x` and `y` */ return typed( name, { 'number, number': bitXorNumber, - 'BigNumber, BigNumber': bigBitXor + 'BigNumber, BigNumber': bigBitXor, + 'bigint, bigint': (x, y) => x ^ y }, matrixAlgorithmSuite({ SS: matAlgo07xSSf, diff --git a/src/function/bitwise/leftShift.js b/src/function/bitwise/leftShift.js index f4abb8b3f3..18b406fc61 100644 --- a/src/function/bitwise/leftShift.js +++ b/src/function/bitwise/leftShift.js @@ -49,9 +49,9 @@ export const createLeftShift = /* #__PURE__ */ factory(name, dependencies, ({ ty * * leftShift, bitNot, bitOr, bitXor, rightArithShift, rightLogShift * - * @param {number | BigNumber | Array | Matrix} x Value to be shifted - * @param {number | BigNumber} y Amount of shifts - * @return {number | BigNumber | Array | Matrix} `x` shifted left `y` times + * @param {number | BigNumber | bigint | Array | Matrix} x Value to be shifted + * @param {number | BigNumber | bigint} y Amount of shifts + * @return {number | BigNumber | bigint | Array | Matrix} `x` shifted left `y` times */ return typed( name, @@ -60,6 +60,8 @@ export const createLeftShift = /* #__PURE__ */ factory(name, dependencies, ({ ty 'BigNumber, BigNumber': leftShiftBigNumber, + 'bigint, bigint': (x, y) => x << y, + 'SparseMatrix, number | BigNumber': typed.referToSelf(self => (x, y) => { // check scalar if (equalScalar(y, 0)) { diff --git a/src/function/bitwise/rightArithShift.js b/src/function/bitwise/rightArithShift.js index 507cd20222..c84a411d06 100644 --- a/src/function/bitwise/rightArithShift.js +++ b/src/function/bitwise/rightArithShift.js @@ -49,9 +49,9 @@ export const createRightArithShift = /* #__PURE__ */ factory(name, dependencies, * * bitAnd, bitNot, bitOr, bitXor, rightArithShift, rightLogShift * - * @param {number | BigNumber | Array | Matrix} x Value to be shifted - * @param {number | BigNumber} y Amount of shifts - * @return {number | BigNumber | Array | Matrix} `x` zero-filled shifted right `y` times + * @param {number | BigNumber | bigint | Array | Matrix} x Value to be shifted + * @param {number | BigNumber | bigint} y Amount of shifts + * @return {number | BigNumber | bigint | Array | Matrix} `x` zero-filled shifted right `y` times */ return typed( name, @@ -60,6 +60,8 @@ export const createRightArithShift = /* #__PURE__ */ factory(name, dependencies, 'BigNumber, BigNumber': rightArithShiftBigNumber, + 'bigint, bigint': (x, y) => x >> y, + 'SparseMatrix, number | BigNumber': typed.referToSelf(self => (x, y) => { // check scalar if (equalScalar(y, 0)) { diff --git a/src/function/logical/and.js b/src/function/logical/and.js index a05af90dda..827751d042 100644 --- a/src/function/logical/and.js +++ b/src/function/logical/and.js @@ -46,8 +46,8 @@ export const createAnd = /* #__PURE__ */ factory(name, dependencies, ({ typed, m * * not, or, xor * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x First value to check - * @param {number | BigNumber | Complex | Unit | Array | Matrix} y Second value to check + * @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 both inputs are defined with a nonzero/nonempty value. */ @@ -64,6 +64,8 @@ export const createAnd = /* #__PURE__ */ factory(name, dependencies, ({ typed, m return !x.isZero() && !y.isZero() && !x.isNaN() && !y.isNaN() }, + 'bigint, bigint': andNumber, + 'Unit, Unit': typed.referToSelf(self => (x, y) => self(x.value || 0, y.value || 0)), diff --git a/src/function/logical/not.js b/src/function/logical/not.js index ab4197f9ed..3706f00b4b 100644 --- a/src/function/logical/not.js +++ b/src/function/logical/not.js @@ -27,7 +27,7 @@ export const createNot = /* #__PURE__ */ factory(name, dependencies, ({ typed }) * * and, or, xor * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x First value to check + * @param {number | BigNumber | bigint | Complex | Unit | Array | Matrix} x First value to check * @return {boolean | Array | Matrix} * Returns true when input is a zero or empty value. */ @@ -44,6 +44,8 @@ export const createNot = /* #__PURE__ */ factory(name, dependencies, ({ typed }) return x.isZero() || x.isNaN() }, + bigint: x => !x, + Unit: typed.referToSelf(self => x => typed.find(self, x.valueType())(x.value)), 'Array | Matrix': typed.referToSelf(self => x => deepMap(x, self)) diff --git a/src/function/logical/or.js b/src/function/logical/or.js index 586e161ed8..12d6c5b48d 100644 --- a/src/function/logical/or.js +++ b/src/function/logical/or.js @@ -43,8 +43,8 @@ export const createOr = /* #__PURE__ */ factory(name, dependencies, ({ typed, ma * * and, not, xor * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x First value to check - * @param {number | BigNumber | Complex | Unit | Array | Matrix} y Second value to check + * @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. */ @@ -61,6 +61,8 @@ export const createOr = /* #__PURE__ */ factory(name, dependencies, ({ typed, ma return (!x.isZero() && !x.isNaN()) || (!y.isZero() && !y.isNaN()) }, + 'bigint, bigint': orNumber, + 'Unit, Unit': typed.referToSelf(self => (x, y) => self(x.value || 0, y.value || 0)) }, diff --git a/src/function/logical/xor.js b/src/function/logical/xor.js index 1bc1256c2d..63418cace9 100644 --- a/src/function/logical/xor.js +++ b/src/function/logical/xor.js @@ -42,8 +42,8 @@ export const createXor = /* #__PURE__ */ factory(name, dependencies, ({ typed, m * * and, not, or * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x First value to check - * @param {number | BigNumber | Complex | Unit | Array | Matrix} y Second value to check + * @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 and only one input is defined with a nonzero/nonempty value. */ @@ -56,6 +56,8 @@ export const createXor = /* #__PURE__ */ factory(name, dependencies, ({ typed, m return ((x.re !== 0 || x.im !== 0) !== (y.re !== 0 || y.im !== 0)) }, + 'bigint, bigint': xorNumber, + 'BigNumber, BigNumber': function (x, y) { return ((!x.isZero() && !x.isNaN()) !== (!y.isZero() && !y.isNaN())) }, diff --git a/src/function/relational/compare.js b/src/function/relational/compare.js index 963f349566..39886c3920 100644 --- a/src/function/relational/compare.js +++ b/src/function/relational/compare.js @@ -58,9 +58,9 @@ export const createCompare = /* #__PURE__ */ factory(name, dependencies, ({ type * * equal, unequal, smaller, smallerEq, larger, largerEq, compareNatural, compareText * - * @param {number | BigNumber | Fraction | Unit | string | Array | Matrix} x First value to compare - * @param {number | BigNumber | Fraction | Unit | string | Array | Matrix} y Second value to compare - * @return {number | BigNumber | Fraction | Array | Matrix} Returns the result of the comparison: + * @param {number | BigNumber | bigint | Fraction | Unit | string | Array | Matrix} x First value to compare + * @param {number | BigNumber | bigint | Fraction | Unit | string | Array | Matrix} y Second value to compare + * @return {number | BigNumber | bigint | Fraction | Array | Matrix} Returns the result of the comparison: * 1 when x > y, -1 when x < y, and 0 when x == y. */ return typed( @@ -77,6 +77,10 @@ export const createCompare = /* #__PURE__ */ factory(name, dependencies, ({ type : new BigNumber(x.cmp(y)) }, + 'bigint, bigint': function (x, y) { + return x === y ? 0n : (x > y ? 1n : -1n) + }, + 'Fraction, Fraction': function (x, y) { return new Fraction(x.compare(y)) }, diff --git a/src/function/relational/equal.js b/src/function/relational/equal.js index e9c2bc36ea..f06281f26b 100644 --- a/src/function/relational/equal.js +++ b/src/function/relational/equal.js @@ -59,8 +59,8 @@ export const createEqual = /* #__PURE__ */ factory(name, dependencies, ({ typed, * * unequal, smaller, smallerEq, larger, largerEq, compare, deepEqual, equalText * - * @param {number | BigNumber | boolean | Complex | Unit | string | Array | Matrix} x First value to compare - * @param {number | BigNumber | boolean | Complex | Unit | string | Array | Matrix} y Second value to compare + * @param {number | BigNumber | bigint | boolean | Complex | Unit | string | Array | Matrix} x First value to compare + * @param {number | BigNumber | bigint | boolean | Complex | Unit | string | Array | Matrix} y Second value to compare * @return {boolean | Array | Matrix} Returns true when the compared values are equal, else returns false */ return typed( diff --git a/src/function/relational/equalScalar.js b/src/function/relational/equalScalar.js index f922fece17..eea6881e4d 100644 --- a/src/function/relational/equalScalar.js +++ b/src/function/relational/equalScalar.js @@ -13,8 +13,8 @@ export const createEqualScalar = /* #__PURE__ */ factory(name, dependencies, ({ /** * Test whether two scalar values are nearly equal. * - * @param {number | BigNumber | Fraction | boolean | Complex | Unit} x First value to compare - * @param {number | BigNumber | Fraction | boolean | Complex} y Second value to compare + * @param {number | BigNumber | bigint | Fraction | boolean | Complex | Unit} x First value to compare + * @param {number | BigNumber | bigint | Fraction | boolean | Complex} y Second value to compare * @return {boolean} Returns true when the compared values are equal, else returns false * @private */ @@ -32,6 +32,10 @@ export const createEqualScalar = /* #__PURE__ */ factory(name, dependencies, ({ return x.eq(y) || bigNearlyEqual(x, y, config.relTol, config.absTol) }, + 'bigint, bigint': function (x, y) { + return x === y + }, + 'Fraction, Fraction': function (x, y) { return x.equals(y) }, diff --git a/src/function/relational/larger.js b/src/function/relational/larger.js index 30303a2104..4325c1b319 100644 --- a/src/function/relational/larger.js +++ b/src/function/relational/larger.js @@ -50,8 +50,8 @@ export const createLarger = /* #__PURE__ */ factory(name, dependencies, ({ typed * * equal, unequal, smaller, smallerEq, largerEq, compare * - * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} x First value to compare - * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare + * @param {number | BigNumber | bigint | Fraction | boolean | Unit | string | Array | Matrix} x First value to compare + * @param {number | BigNumber | bigint | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare * @return {boolean | Array | Matrix} Returns true when the x is larger than y, else returns false */ return typed( @@ -64,6 +64,8 @@ export const createLarger = /* #__PURE__ */ factory(name, dependencies, ({ typed return x.gt(y) && !bigNearlyEqual(x, y, config.relTol, config.absTol) }, + 'bigint, bigint': (x, y) => x > y, + 'Fraction, Fraction': (x, y) => (x.compare(y) === 1), 'Complex, Complex': function () { diff --git a/src/function/relational/largerEq.js b/src/function/relational/largerEq.js index 9f645e99e6..5872df18c7 100644 --- a/src/function/relational/largerEq.js +++ b/src/function/relational/largerEq.js @@ -46,8 +46,8 @@ export const createLargerEq = /* #__PURE__ */ factory(name, dependencies, ({ typ * * equal, unequal, smaller, smallerEq, larger, compare * - * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} x First value to compare - * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare + * @param {number | BigNumber | bigint | Fraction | boolean | Unit | string | Array | Matrix} x First value to compare + * @param {number | BigNumber | bigint | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare * @return {boolean | Array | Matrix} Returns true when the x is larger or equal to y, else returns false */ return typed( @@ -60,6 +60,10 @@ export const createLargerEq = /* #__PURE__ */ factory(name, dependencies, ({ typ return x.gte(y) || bigNearlyEqual(x, y, config.relTol, config.absTol) }, + 'bigint, bigint': function (x, y) { + return x >= y + }, + 'Fraction, Fraction': (x, y) => (x.compare(y) !== -1), 'Complex, Complex': function () { diff --git a/src/function/relational/smaller.js b/src/function/relational/smaller.js index 4894aded66..8b9412b58c 100644 --- a/src/function/relational/smaller.js +++ b/src/function/relational/smaller.js @@ -50,8 +50,8 @@ export const createSmaller = /* #__PURE__ */ factory(name, dependencies, ({ type * * equal, unequal, smallerEq, smaller, smallerEq, compare * - * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} x First value to compare - * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare + * @param {number | BigNumber | bigint | Fraction | boolean | Unit | string | Array | Matrix} x First value to compare + * @param {number | BigNumber | bigint | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare * @return {boolean | Array | Matrix} Returns true when the x is smaller than y, else returns false */ return typed( @@ -64,6 +64,8 @@ export const createSmaller = /* #__PURE__ */ factory(name, dependencies, ({ type return x.lt(y) && !bigNearlyEqual(x, y, config.relTol, config.absTol) }, + 'bigint, bigint': (x, y) => x < y, + 'Fraction, Fraction': (x, y) => (x.compare(y) === -1), 'Complex, Complex': function (x, y) { diff --git a/src/function/relational/smallerEq.js b/src/function/relational/smallerEq.js index 7656ba9d4a..bfef89983d 100644 --- a/src/function/relational/smallerEq.js +++ b/src/function/relational/smallerEq.js @@ -46,8 +46,8 @@ export const createSmallerEq = /* #__PURE__ */ factory(name, dependencies, ({ ty * * equal, unequal, smaller, larger, largerEq, compare * - * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} x First value to compare - * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare + * @param {number | BigNumber | bigint | Fraction | boolean | Unit | string | Array | Matrix} x First value to compare + * @param {number | BigNumber | bigint | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare * @return {boolean | Array | Matrix} Returns true when the x is smaller than y, else returns false */ return typed( @@ -60,6 +60,8 @@ export const createSmallerEq = /* #__PURE__ */ factory(name, dependencies, ({ ty return x.lte(y) || bigNearlyEqual(x, y, config.relTol, config.absTol) }, + 'bigint, bigint': (x, y) => (x <= y), + 'Fraction, Fraction': (x, y) => (x.compare(y) !== 1), 'Complex, Complex': function () { diff --git a/src/function/statistics/max.js b/src/function/statistics/max.js index e85707b0cd..4dd3062105 100644 --- a/src/function/statistics/max.js +++ b/src/function/statistics/max.js @@ -1,5 +1,6 @@ import { deepForEach, reduce, containsCollections } from '../../utils/collection.js' import { factory } from '../../utils/factory.js' +import { safeNumberType } from '../../utils/number.js' import { improveErrorMessage } from './utils/improveErrorMessage.js' const name = 'max' @@ -98,7 +99,7 @@ export const createMax = /* #__PURE__ */ factory(name, dependencies, ({ typed, c // make sure returning numeric value: parse a string into a numeric value if (typeof res === 'string') { - res = numeric(res, config.number) + res = numeric(res, safeNumberType(res, config)) } return res diff --git a/src/function/statistics/min.js b/src/function/statistics/min.js index b913cadd24..20145ede48 100644 --- a/src/function/statistics/min.js +++ b/src/function/statistics/min.js @@ -1,5 +1,6 @@ import { containsCollections, deepForEach, reduce } from '../../utils/collection.js' import { factory } from '../../utils/factory.js' +import { safeNumberType } from '../../utils/number.js' import { improveErrorMessage } from './utils/improveErrorMessage.js' const name = 'min' @@ -98,7 +99,7 @@ export const createMin = /* #__PURE__ */ factory(name, dependencies, ({ typed, c // make sure returning numeric value: parse a string into a numeric value if (typeof min === 'string') { - min = numeric(min, config.number) + min = numeric(min, safeNumberType(min, config)) } return min diff --git a/src/function/statistics/prod.js b/src/function/statistics/prod.js index 4ef03b232f..1a5ba84072 100644 --- a/src/function/statistics/prod.js +++ b/src/function/statistics/prod.js @@ -1,5 +1,6 @@ import { deepForEach } from '../../utils/collection.js' import { factory } from '../../utils/factory.js' +import { safeNumberType } from '../../utils/number.js' import { improveErrorMessage } from './utils/improveErrorMessage.js' const name = 'prod' @@ -67,7 +68,7 @@ export const createProd = /* #__PURE__ */ factory(name, dependencies, ({ typed, // make sure returning numeric value: parse a string into a numeric value if (typeof prod === 'string') { - prod = numeric(prod, config.number) + prod = numeric(prod, safeNumberType(prod, config)) } if (prod === undefined) { diff --git a/src/function/statistics/sum.js b/src/function/statistics/sum.js index 6e7374c0dd..5973d19e74 100644 --- a/src/function/statistics/sum.js +++ b/src/function/statistics/sum.js @@ -1,5 +1,6 @@ import { containsCollections, deepForEach, reduce } from '../../utils/collection.js' import { factory } from '../../utils/factory.js' +import { safeNumberType } from '../../utils/number.js' import { improveErrorMessage } from './utils/improveErrorMessage.js' const name = 'sum' @@ -69,7 +70,7 @@ export const createSum = /* #__PURE__ */ factory(name, dependencies, ({ typed, c sum = numeric(0, config.number) } if (typeof sum === 'string') { - sum = numeric(sum, config.number) + sum = numeric(sum, safeNumberType(sum, config)) } return sum diff --git a/src/function/utils/hasNumericValue.js b/src/function/utils/hasNumericValue.js index 27010083e2..0e2cabe733 100644 --- a/src/function/utils/hasNumericValue.js +++ b/src/function/utils/hasNumericValue.js @@ -19,7 +19,9 @@ export const createHasNumericValue = /* #__PURE__ */ factory(name, dependencies, * math.hasNumericValue('2') // returns true * math.isNumeric('2') // returns false * math.hasNumericValue(0) // returns true - * math.hasNumericValue(math.bignumber(500)) // returns true + * math.hasNumericValue(math.bignumber('500')) // returns true + * math.hasNumericValue(math.bigint('42')) // returns true + * math.hasNumericValue(42n) // returns true * math.hasNumericValue(math.fraction(4)) // returns true * math.hasNumericValue(math.complex('2-4i')) // returns false * math.hasNumericValue(false) // returns true diff --git a/src/function/utils/isInteger.js b/src/function/utils/isInteger.js index f81f9b3ff9..f6814d18ab 100644 --- a/src/function/utils/isInteger.js +++ b/src/function/utils/isInteger.js @@ -31,7 +31,7 @@ export const createIsInteger = /* #__PURE__ */ factory(name, dependencies, ({ ty * * isNumeric, isPositive, isNegative, isZero * - * @param {number | BigNumber | Fraction | Array | Matrix} x Value to be tested + * @param {number | BigNumber | bigint | Fraction | Array | Matrix} x Value to be tested * @return {boolean} Returns true when `x` contains a numeric, integer value. * Throws an error in case of an unknown data type. */ @@ -42,6 +42,10 @@ export const createIsInteger = /* #__PURE__ */ factory(name, dependencies, ({ ty return x.isInt() }, + bigint: function (x) { + return true + }, + Fraction: function (x) { return x.d === 1 && isFinite(x.n) }, diff --git a/src/function/utils/isNaN.js b/src/function/utils/isNaN.js index 36e985d695..d334262a8a 100644 --- a/src/function/utils/isNaN.js +++ b/src/function/utils/isNaN.js @@ -31,7 +31,7 @@ export const createIsNaN = /* #__PURE__ */ factory(name, dependencies, ({ typed * * isNumeric, isNegative, isPositive, isZero, isInteger * - * @param {number | BigNumber | Fraction | Unit | Array | Matrix} x Value to be tested + * @param {number | BigNumber | bigint | Fraction | Unit | Array | Matrix} x Value to be tested * @return {boolean} Returns true when `x` is NaN. * Throws an error in case of an unknown data type. */ @@ -42,6 +42,10 @@ export const createIsNaN = /* #__PURE__ */ factory(name, dependencies, ({ typed return x.isNaN() }, + bigint: function (x) { + return false + }, + Fraction: function (x) { return false }, diff --git a/src/function/utils/isNegative.js b/src/function/utils/isNegative.js index 9fcda137ba..95126a8715 100644 --- a/src/function/utils/isNegative.js +++ b/src/function/utils/isNegative.js @@ -33,7 +33,7 @@ export const createIsNegative = /* #__PURE__ */ factory(name, dependencies, ({ t * * isNumeric, isPositive, isZero, isInteger * - * @param {number | BigNumber | Fraction | Unit | Array | Matrix} x Value to be tested + * @param {number | BigNumber | bigint | Fraction | Unit | Array | Matrix} x Value to be tested * @return {boolean} Returns true when `x` is larger than zero. * Throws an error in case of an unknown data type. */ @@ -44,6 +44,8 @@ export const createIsNegative = /* #__PURE__ */ factory(name, dependencies, ({ t ? false : x.isNeg() && !x.isZero() && !x.isNaN(), + bigint: x => x < 0n, + Fraction: x => x.s < 0, // It's enough to decide on the sign Unit: typed.referToSelf(self => diff --git a/src/function/utils/isNumeric.js b/src/function/utils/isNumeric.js index 2418b55c5b..da280c6d70 100644 --- a/src/function/utils/isNumeric.js +++ b/src/function/utils/isNumeric.js @@ -20,7 +20,8 @@ export const createIsNumeric = /* #__PURE__ */ factory(name, dependencies, ({ ty * math.isNumeric('2') // returns false * math.hasNumericValue('2') // returns true * math.isNumeric(0) // returns true - * math.isNumeric(math.bignumber(500)) // returns true + * math.isNumeric(math.bignumber('42')) // returns true + * math.isNumeric(math.bigint('42')) // returns true * math.isNumeric(math.fraction(4)) // returns true * math.isNumeric(math.complex('2-4i')) // returns false * math.isNumeric([2.3, 'foo', false]) // returns [true, false, true] @@ -35,7 +36,7 @@ export const createIsNumeric = /* #__PURE__ */ factory(name, dependencies, ({ ty * Throws an error in case of unknown types. */ return typed(name, { - 'number | BigNumber | Fraction | boolean': () => true, + 'number | BigNumber | bigint | Fraction | boolean': () => true, 'Complex | Unit | string | null | undefined | Node': () => false, 'Array | Matrix': typed.referToSelf(self => x => deepMap(x, self)) }) diff --git a/src/function/utils/isPositive.js b/src/function/utils/isPositive.js index 63245dc1eb..9ce3d3c56a 100644 --- a/src/function/utils/isPositive.js +++ b/src/function/utils/isPositive.js @@ -35,7 +35,7 @@ export const createIsPositive = /* #__PURE__ */ factory(name, dependencies, ({ t * * isNumeric, isZero, isNegative, isInteger * - * @param {number | BigNumber | Fraction | Unit | Array | Matrix} x Value to be tested + * @param {number | BigNumber | bigint | Fraction | Unit | Array | Matrix} x Value to be tested * @return {boolean} Returns true when `x` is larger than zero. * Throws an error in case of an unknown data type. */ @@ -47,6 +47,8 @@ export const createIsPositive = /* #__PURE__ */ factory(name, dependencies, ({ t ? false : !x.isNeg() && !x.isZero() && !x.isNaN(), + bigint: x => x > 0n, + Fraction: x => x.s > 0 && x.n > 0, Unit: typed.referToSelf(self => diff --git a/src/function/utils/isPrime.js b/src/function/utils/isPrime.js index f04f853155..b1434ccbdd 100644 --- a/src/function/utils/isPrime.js +++ b/src/function/utils/isPrime.js @@ -29,15 +29,12 @@ export const createIsPrime = /* #__PURE__ */ factory(name, dependencies, ({ type * * isNumeric, isZero, isNegative, isInteger * - * @param {number | BigNumber | Array | Matrix} x Value to be tested + * @param {number | BigNumber | bigint | Array | Matrix} x Value to be tested * @return {boolean} Returns true when `x` is larger than zero. * Throws an error in case of an unknown data type. */ return typed(name, { number: function (x) { - if (x * 0 !== 0) { - return false - } if (x <= 3) { return x > 1 } @@ -52,10 +49,22 @@ export const createIsPrime = /* #__PURE__ */ factory(name, dependencies, ({ type return true }, - BigNumber: function (n) { - if (n.toNumber() * 0 !== 0) { + bigint: function (x) { + if (x <= 3n) { + return x > 1n + } + if (x % 2n === 0n || x % 3n === 0n) { return false } + for (let i = 5n; i * i <= x; i += 6n) { + if (x % i === 0n || x % (i + 2n) === 0n) { + return false + } + } + return true + }, + + BigNumber: function (n) { if (n.lte(3)) return n.gt(1) if (n.mod(2).eq(0) || n.mod(3).eq(0)) return false if (n.lt(Math.pow(2, 32))) { diff --git a/src/function/utils/isZero.js b/src/function/utils/isZero.js index ea3572f593..deb113ff59 100644 --- a/src/function/utils/isZero.js +++ b/src/function/utils/isZero.js @@ -34,13 +34,15 @@ export const createIsZero = /* #__PURE__ */ factory(name, dependencies, ({ typed * * isNumeric, isPositive, isNegative, isInteger * - * @param {number | BigNumber | Complex | Fraction | Unit | Array | Matrix} x Value to be tested + * @param {number | BigNumber | bigint | Complex | Fraction | Unit | Array | Matrix} x Value to be tested * @return {boolean} Returns true when `x` is zero. * Throws an error in case of an unknown data type. */ return typed(name, { 'number | BigNumber | Complex | Fraction': x => equalScalar(x, 0), + bigint: x => x === 0n, + Unit: typed.referToSelf(self => x => typed.find(self, x.valueType())(x.value)), diff --git a/src/function/utils/numeric.js b/src/function/utils/numeric.js index 2cf29cb05d..e9cb5a24f2 100644 --- a/src/function/utils/numeric.js +++ b/src/function/utils/numeric.js @@ -19,13 +19,14 @@ export const createNumeric = /* #__PURE__ */ factory(name, dependencies, ({ numb BigNumber: bignumber ? (x) => bignumber(x) : noBignumber, + bigint: (x) => BigInt(x), Fraction: fraction ? (x) => fraction(x) : noFraction } /** - * Convert a numeric input to a specific numeric type: number, BigNumber, or Fraction. + * Convert a numeric input to a specific numeric type: number, BigNumber, bigint, or Fraction. * * Syntax: * @@ -35,6 +36,7 @@ export const createNumeric = /* #__PURE__ */ factory(name, dependencies, ({ numb * * math.numeric('4') // returns 4 * math.numeric('4', 'number') // returns 4 + * math.numeric('4', 'bigint') // returns 4n * math.numeric('4', 'BigNumber') // returns BigNumber 4 * math.numeric('4', 'Fraction') // returns Fraction 4 * math.numeric(4, 'Fraction') // returns Fraction 4 @@ -42,14 +44,14 @@ export const createNumeric = /* #__PURE__ */ factory(name, dependencies, ({ numb * * See also: * - * number, fraction, bignumber, string, format + * number, fraction, bignumber, bigint, string, format * - * @param {string | number | BigNumber | Fraction } value + * @param {string | number | BigNumber | bigint | Fraction } value * A numeric value or a string containing a numeric value * @param {string} outputType * Desired numeric output type. * Available values: 'number', 'BigNumber', or 'Fraction' - * @return {number | BigNumber | Fraction} + * @return {number | BigNumber | bigint | Fraction} * Returns an instance of the numeric in the requested type */ return function numeric (value, outputType = 'number', check) { diff --git a/src/function/utils/typeOf.js b/src/function/utils/typeOf.js index 8ca1f44489..a60a6bdcbd 100644 --- a/src/function/utils/typeOf.js +++ b/src/function/utils/typeOf.js @@ -17,6 +17,7 @@ export const createTypeOf = /* #__PURE__ */ factory(name, dependencies, ({ typed * // This list is intended to include all relevant types, for testing * // purposes: * math.typeOf(3.5) // returns 'number' + * math.typeOf(42n) // returns 'bigint' * math.typeOf(math.complex('2-4i')) // returns 'Complex' * math.typeOf(math.unit('45 deg')) // returns 'Unit' * math.typeOf('hello world') // returns 'string' diff --git a/src/json/replacer.js b/src/json/replacer.js index 2f928e449d..e085d82243 100644 --- a/src/json/replacer.js +++ b/src/json/replacer.js @@ -25,6 +25,13 @@ export const createReplacer = /* #__PURE__ */ factory(name, dependencies, () => } } + if (typeof value === 'bigint') { + return { + mathjs: 'bigint', + value: String(value) + } + } + return value } }) diff --git a/src/type/bigint.js b/src/type/bigint.js new file mode 100644 index 0000000000..2b5e90625c --- /dev/null +++ b/src/type/bigint.js @@ -0,0 +1,72 @@ +import { factory } from '../utils/factory.js' +import { deepMap } from '../utils/collection.js' + +const name = 'bigint' +const dependencies = ['typed'] + +export const createBigint = /* #__PURE__ */ factory(name, dependencies, ({ typed }) => { + /** + * Create a bigint or convert a string, boolean, or unit to a bigint. + * When value is a matrix, all elements will be converted to bigint. + * + * Syntax: + * + * math.bigint(value) + * + * Examples: + * + * math.bigint(2) // returns 2n + * math.bigint('123') // returns 123n + * math.bigint(true) // returns 1n + * math.bigint([true, false, true, true]) // returns [1n, 0n, 1n, 1n] + * + * See also: + * + * number, bignumber, boolean, complex, index, matrix, string, unit + * + * @param {string | number | BigNumber | bigint | Fraction | boolean | Array | Matrix | null} [value] Value to be converted + * @return {bigint | Array | Matrix} The created bigint + */ + const bigint = typed('bigint', { + '': function () { + return 0n + }, + + bigint: function (x) { + return x + }, + + number: function (x) { + return BigInt(x.toFixed()) + }, + + BigNumber: function (x) { + return BigInt(x.round().toString()) + }, + + Fraction: function (x) { + return BigInt(x.valueOf().toFixed()) + }, + + 'string | boolean': function (x) { + return BigInt(x) + }, + + null: function (x) { + return 0n + }, + + 'Array | Matrix': typed.referToSelf(self => x => deepMap(x, self)) + }) + + // reviver function to parse a JSON object like: + // + // {"mathjs":"bigint","value":"123"} + // + // into a bigint 123n + bigint.fromJSON = function (json) { + return BigInt(json.value) + } + + return bigint +}) diff --git a/src/type/bignumber/function/bignumber.js b/src/type/bignumber/function/bignumber.js index e469563b15..49391bebaa 100644 --- a/src/type/bignumber/function/bignumber.js +++ b/src/type/bignumber/function/bignumber.js @@ -24,9 +24,9 @@ export const createBignumber = /* #__PURE__ */ factory(name, dependencies, ({ ty * * See also: * - * boolean, complex, index, matrix, string, unit + * number, bigint, boolean, complex, index, matrix, string, unit * - * @param {number | string | Fraction | BigNumber | Array | Matrix | boolean | null} [value] Value for the big number, + * @param {number | string | Fraction | BigNumber | bigint | Array | Matrix | boolean | null} [value] Value for the big number, * 0 by default. * @returns {BigNumber} The created bignumber */ @@ -65,6 +65,10 @@ export const createBignumber = /* #__PURE__ */ factory(name, dependencies, ({ ty return x }, + bigint: function (x) { + return new BigNumber(x.toString()) + }, + Unit: typed.referToSelf(self => (x) => { const clone = x.clone() clone.value = self(x.value) diff --git a/src/type/fraction/function/fraction.js b/src/type/fraction/function/fraction.js index 02e748d3b6..1dfb88030a 100644 --- a/src/type/fraction/function/fraction.js +++ b/src/type/fraction/function/fraction.js @@ -37,7 +37,7 @@ export const createFraction = /* #__PURE__ */ factory(name, dependencies, ({ typ * * bignumber, number, string, unit * - * @param {number | string | Fraction | BigNumber | Unit | Array | Matrix} [args] + * @param {number | string | Fraction | BigNumber | bigint | Unit | Array | Matrix} [args] * Arguments specifying the value, or numerator and denominator of * the fraction * @return {Fraction | Array | Matrix} Returns a fraction @@ -67,6 +67,10 @@ export const createFraction = /* #__PURE__ */ factory(name, dependencies, ({ typ return new Fraction(x.toString()) }, + bigint: function (x) { + return new Fraction(x.toString()) + }, + Fraction: function (x) { return x // fractions are immutable }, diff --git a/src/type/number.js b/src/type/number.js index cf21703c68..41b0864c33 100644 --- a/src/type/number.js +++ b/src/type/number.js @@ -60,7 +60,7 @@ export const createNumber = /* #__PURE__ */ factory(name, dependencies, ({ typed * * See also: * - * bignumber, boolean, complex, index, matrix, string, unit + * bignumber, bigint, boolean, numeric, complex, index, matrix, string, unit * * @param {string | number | BigNumber | Fraction | boolean | Array | Matrix | Unit | null} [value] Value to be converted * @param {Unit | string} [valuelessUnit] A valueless unit, used to convert a unit to a number @@ -112,6 +112,10 @@ export const createNumber = /* #__PURE__ */ factory(name, dependencies, ({ typed return x.toNumber() }, + bigint: function (x) { + return Number(x) + }, + Fraction: function (x) { return x.valueOf() }, diff --git a/src/utils/is.js b/src/utils/is.js index 3b6e681b3f..7c053685ca 100644 --- a/src/utils/is.js +++ b/src/utils/is.js @@ -42,6 +42,10 @@ export function isBigNumber (x) { return false } +export function isBigInt (x) { + return typeof x === 'bigint' +} + export function isComplex (x) { return (x && typeof x === 'object' && Object.getPrototypeOf(x).isComplex === true) || false } diff --git a/src/utils/latex.js b/src/utils/latex.js index e2dac2c566..210e1e9d8d 100644 --- a/src/utils/latex.js +++ b/src/utils/latex.js @@ -267,6 +267,10 @@ export const latexFunctions = { 0: '0', 1: '\\left(${args[0]}\\right)' }, + bigint: { + 0: '0', + 1: '\\left(${args[0]}\\right)' + }, complex: { 0: '0', 1: '\\left(${args[0]}\\right)', diff --git a/src/utils/number.js b/src/utils/number.js index e1e4662ac4..5095b71628 100644 --- a/src/utils/number.js +++ b/src/utils/number.js @@ -19,6 +19,42 @@ export function isInteger (value) { : false } +/** + * Check if a string contains an integer + * @param {string} str + * @return {boolean} isInteger + */ +export function isIntegerStr (str) { + // regex matching strings like "123" and "-123" + return /^-?\d+$/.test(str) +} + +/** + * Ensure the number type is compatible with the provided value. + * If not, return 'number' instead. + * + * For example: + * + * safeNumberType('2.3', { number: 'bigint', numberFallback: 'number' }) + * + * will return 'number' and not 'bigint' because trying to create a bigint with + * value 2.3 would throw an exception. + * + * @param {string} numberStr + * @param {{ + * number: 'number' | 'BigNumber' | 'bigint' | 'Fraction' + * numberFallback: 'number' | 'BigNumber' + * }} config + * @returns {'number' | 'BigNumber' | 'bigint' | 'Fraction'} + */ +export function safeNumberType (numberStr, config) { + if (config.number === 'bigint' && !isIntegerStr(numberStr)) { + return config.numberFallback + } + + return config.number +} + /** * Calculate the sign of a number * @param {number} x diff --git a/src/utils/object.js b/src/utils/object.js index 5fd54dd1d0..ffb374022b 100644 --- a/src/utils/object.js +++ b/src/utils/object.js @@ -15,7 +15,7 @@ export function clone (x) { const type = typeof x // immutable primitive types - if (type === 'number' || type === 'string' || type === 'boolean' || + if (type === 'number' || type === 'bigint' || type === 'string' || type === 'boolean' || x === null || x === undefined) { return x } diff --git a/test/browser-test-config/base-karma.js b/test/browser-test-config/base-karma.js index 254caaa87c..aab2e91600 100644 --- a/test/browser-test-config/base-karma.js +++ b/test/browser-test-config/base-karma.js @@ -7,7 +7,6 @@ module.exports = function (config) { frameworks: [ 'mocha' - // 'webpack' TODO: needed after upgrading to webpack 5, see https://github.com/josdejong/mathjs/pull/2433 ], // list of files / patterns to load in the browser diff --git a/test/node-tests/doc.test.js b/test/node-tests/doc.test.js index f6324cec2b..f0333fb6e4 100644 --- a/test/node-tests/doc.test.js +++ b/test/node-tests/doc.test.js @@ -163,6 +163,7 @@ const knownUndocumented = new Set([ 'isNumber', 'isComplex', 'isBigNumber', + 'isBigInt', 'isFraction', 'isUnit', 'isString', @@ -278,6 +279,7 @@ const knownUndocumented = new Set([ 'nuclearMagneton', 'null', 'number', + 'bigint', 'ObjectNode', 'OperatorNode', 'ParenthesisNode', diff --git a/test/typescript-tests/testTypes.ts b/test/typescript-tests/testTypes.ts index caa78be3e8..2f6efe1c92 100644 --- a/test/typescript-tests/testTypes.ts +++ b/test/typescript-tests/testTypes.ts @@ -261,6 +261,13 @@ Chaining examples MathJsChain >() + // bigint + expectTypeOf(math.chain(math.bigint(12))).toMatchTypeOf>() + expectTypeOf(math.chain(12).bigint()).toMatchTypeOf>() + expectTypeOf(math.chain([12, 13, 14]).bigint()).toMatchTypeOf< + MathJsChain + >() + // chain expectTypeOf(math.chain(12).bignumber().clone()).toMatchTypeOf< MathJsChain @@ -334,6 +341,14 @@ Chaining examples MathJsChain >() + // numeric + expectTypeOf(math.chain('12').numeric('bigint')).toMatchTypeOf< + MathJsChain + >() + expectTypeOf(math.chain(12).numeric('BigNumber')).toMatchTypeOf< + MathJsChain + >() + // sparse expectTypeOf(math.chain([12, 13, 14, 15]).sparse()).toMatchTypeOf< MathJsChain @@ -2470,7 +2485,7 @@ Statistics functions' return types math.min([math.unit('5cm'), math.unit('10cm')]) ).toMatchTypeOf() expectTypeOf(math.min(123, math.bignumber('456'))).toMatchTypeOf< - number | BigNumber | Fraction | Complex | Unit + number | BigNumber | bigint | Fraction | Complex | Unit >() expectTypeOf( math.min( @@ -2509,7 +2524,7 @@ Statistics functions' return types math.mean([math.unit('5cm'), math.unit('10cm')]) ).toMatchTypeOf() expectTypeOf(math.mean(123, math.bignumber('456'))).toMatchTypeOf< - number | BigNumber | Fraction | Complex | Unit + number | BigNumber | bigint | Fraction | Complex | Unit >() expectTypeOf(math.median(1, 2, 3)).toMatchTypeOf() @@ -2524,7 +2539,7 @@ Statistics functions' return types math.median([math.unit('5cm'), math.unit('10cm')]) ).toMatchTypeOf() expectTypeOf(math.median(123, math.bignumber('456'))).toMatchTypeOf< - number | BigNumber | Fraction | Complex | Unit + number | BigNumber | bigint | Fraction | Complex | Unit >() expectTypeOf(math.quantileSeq([1, 2, 3], 0.75)).toMatchTypeOf() diff --git a/test/unit-tests/core/typed.test.js b/test/unit-tests/core/typed.test.js index 883cbcadd9..98dea5d0ec 100644 --- a/test/unit-tests/core/typed.test.js +++ b/test/unit-tests/core/typed.test.js @@ -39,6 +39,14 @@ describe('typed', function () { assert.strictEqual(math.isBigNumber(), false) }) + it('should test whether a value is a bigint', function () { + assert.strictEqual(math.isBigInt(2n), true) + assert.strictEqual(math.isBigInt(BigInt(2)), true) + assert.strictEqual(math.isBigInt(2), false) + assert.strictEqual(math.isBigInt(null), false) + assert.strictEqual(math.isBigInt(), false) + }) + it('should recognize a Decimal as a BigNumber', function () { assert.strictEqual(math.isBigNumber(Decimal(2)), true) assert.strictEqual(math.isBigNumber(Decimal('2.6666666')), true) @@ -329,4 +337,33 @@ describe('typed', function () { assert.strictEqual(math.isChain(2), false) assert.strictEqual(math.isChain(), false) }) + + it('should convert a bigint to number if possible', function () { + const double = math.typed('double', { + number: (x) => x + x + }) + + assert.strictEqual(double(2), 4) + assert.strictEqual(double(2n), 4) + assert.throws(() => double(12345678901234567890n), /value exceeds the max safe integer/) + }) + + it('should convert a bigint to BigNumber', function () { + const double = math.typed('double', { + BigNumber: (x) => x.plus(x) + }) + + assert.deepStrictEqual(double(math.bignumber(2)), math.bignumber(4)) + assert.deepStrictEqual(double(2n), math.bignumber(4)) + assert.deepStrictEqual(double(12345678901234567890n), math.bignumber('24691357802469135780')) + }) + + it('should convert a bigint to Fraction', function () { + const double = math.typed('double', { + Fraction: (x) => x.add(x) + }) + + assert.deepStrictEqual(double(math.fraction(2)), math.fraction(4)) + assert.deepStrictEqual(double(2n), math.fraction(4)) + }) }) diff --git a/test/unit-tests/expression/node/ConstantNode.test.js b/test/unit-tests/expression/node/ConstantNode.test.js index c4928d9a40..68d74020bf 100644 --- a/test/unit-tests/expression/node/ConstantNode.test.js +++ b/test/unit-tests/expression/node/ConstantNode.test.js @@ -15,6 +15,7 @@ describe('ConstantNode', function () { // TODO: extensively test each of the supported types assert.strictEqual(new ConstantNode(3).value, 3) + assert.strictEqual(new ConstantNode(3n).value, 3n) assert.strictEqual(new ConstantNode('hello').value, 'hello') assert.strictEqual(new ConstantNode(true).value, true) assert.strictEqual(new ConstantNode(false).value, false) @@ -38,6 +39,9 @@ describe('ConstantNode', function () { expr = new ConstantNode(2.3).compile() assert.strictEqual(expr.evaluate(), 2.3) + expr = new ConstantNode(4n).compile() + assert.strictEqual(expr.evaluate(), 4n) + expr = new ConstantNode('hello').compile() assert.strictEqual(expr.evaluate(), 'hello') @@ -135,6 +139,7 @@ describe('ConstantNode', function () { it('should stringify a ConstantNode', function () { assert.strictEqual(new ConstantNode(3).toString(), '3') assert.deepStrictEqual(new ConstantNode(3).toString(), '3') + assert.deepStrictEqual(new ConstantNode(3n).toString(), '3') assert.deepStrictEqual(new ConstantNode(math.bignumber('1e500')).toString(), '1e+500') assert.deepStrictEqual(new ConstantNode(math.fraction(2, 3)).toString(), '2/3') assert.strictEqual(new ConstantNode('hi').toString(), '"hi"') @@ -188,6 +193,7 @@ describe('ConstantNode', function () { it('should LaTeX a ConstantNode', function () { assert.strictEqual(new ConstantNode(3).toTex(), '3') assert.deepStrictEqual(new ConstantNode(3).toTex(), '3') + assert.deepStrictEqual(new ConstantNode(42n).toTex(), '42') assert.deepStrictEqual(new ConstantNode(math.bignumber('3')).toTex(), '3') assert.deepStrictEqual(new ConstantNode(math.bignumber('1.3e7')).toTex(), '1.3\\cdot10^{+7}') assert.deepStrictEqual(new ConstantNode(math.bignumber('1e500')).toTex(), '1\\cdot10^{+500}') diff --git a/test/unit-tests/expression/parse.test.js b/test/unit-tests/expression/parse.test.js index b3de860cfc..57c616217c 100644 --- a/test/unit-tests/expression/parse.test.js +++ b/test/unit-tests/expression/parse.test.js @@ -2144,6 +2144,37 @@ describe('parse', function () { }) }) + describe('bigint', function () { + const bigmath = math.create({ + number: 'bigint' + }) + + it('should parse integer numbers as bigint', function () { + assert.strictEqual(bigmath.evaluate('123123123123123123123'), 123123123123123123123n) + assert.strictEqual(bigmath.evaluate('-123123123123123123123'), -123123123123123123123n) + assert.strictEqual(bigmath.evaluate('2.3'), 2.3) + assert.strictEqual(bigmath.evaluate('-2.3'), -2.3) + }) + + it('should fallback on the configured numberFallback when parsing as bigint', function () { + const bigmathFallback = math.create({ + number: 'bigint', + numberFallback: 'BigNumber' + }) + + assert.strictEqual(bigmathFallback.evaluate('42'), 42n) + assert.deepStrictEqual(bigmathFallback.evaluate('2.3'), bigmathFallback.bignumber('2.3')) + assert.deepStrictEqual(bigmathFallback.evaluate('-2.3'), bigmathFallback.bignumber('-2.3')) + }) + + it('should evaluate units with bigint values (falling back to number)', function () { + assert.strictEqual(bigmath.evaluate('5 mm').toString(), '5 mm') + assert.strictEqual(bigmath.evaluate('5.5 mm').toString(), '5.5 mm') + assert.strictEqual(bigmath.evaluate('2 * 5 mm').toString(), '10 mm') + assert.strictEqual(bigmath.evaluate('2.5 * 4 mm').toString(), '10 mm') + }) + }) + describe('scope', function () { it('should use a given scope for assignments', function () { const scope = { diff --git a/test/unit-tests/function/algebra/simplify.test.js b/test/unit-tests/function/algebra/simplify.test.js index 9c77025574..6327f46011 100644 --- a/test/unit-tests/function/algebra/simplify.test.js +++ b/test/unit-tests/function/algebra/simplify.test.js @@ -279,6 +279,12 @@ describe('simplify', function () { assert.deepStrictEqual(bigmath.simplify('3 + 1 / 11111111111111111111').evaluate(), bigmath.evaluate('3 + 1 / 11111111111111111111')) }) + it('should preserve the value of bigints', function () { + const bigmath = math.create({ number: 'bigint' }) + assert.deepStrictEqual(bigmath.simplify('70000000000000000123 + 1').evaluate(), 70000000000000000124n) + assert.deepStrictEqual(bigmath.simplify('70000000000000000123 + 5e3').evaluate(), 70000000000000010000) + }) + it('should not change the value of numbers when converting to fractions (1)', function () { simplifyAndCompareEval('1e-10', '1e-10') }) diff --git a/test/unit-tests/function/arithmetic/abs.test.js b/test/unit-tests/function/arithmetic/abs.test.js index f1392927e9..d57ede19ac 100644 --- a/test/unit-tests/function/arithmetic/abs.test.js +++ b/test/unit-tests/function/arithmetic/abs.test.js @@ -19,6 +19,12 @@ describe('abs', function () { assert.strictEqual(abs(0), 0) }) + it('should return the abs value of a bigint', function () { + assert.strictEqual(abs(-4n), 4n) + assert.strictEqual(abs(4n), 4n) + assert.strictEqual(abs(0n), 0n) + }) + it('should return the absolute value of a big number', function () { assert.deepStrictEqual(abs(bignumber(-2.3)), bignumber(2.3)) assert.deepStrictEqual(abs(bignumber('5e500')), bignumber('5e500')) diff --git a/test/unit-tests/function/arithmetic/addScalar.test.js b/test/unit-tests/function/arithmetic/addScalar.test.js index e15c81a86c..1aa8a46be2 100644 --- a/test/unit-tests/function/arithmetic/addScalar.test.js +++ b/test/unit-tests/function/arithmetic/addScalar.test.js @@ -15,6 +15,10 @@ describe('addScalar', function () { assert.strictEqual(add(-5, -3), -8) }) + it('should add bigint', function () { + assert.strictEqual(add(2n, 3n), 5n) + }) + it('should add booleans', function () { assert.strictEqual(add(true, true), 2) assert.strictEqual(add(true, false), 1) @@ -33,6 +37,14 @@ describe('addScalar', function () { assert.strictEqual(add(false, 2), 2) }) + it('should add mixed numbers and bigint', function () { + assert.strictEqual(add(2, 3n), 5) + assert.strictEqual(add(2n, 3), 5) + + assert.throws(function () { add(123123123123123123123n, 1) }, /Cannot implicitly convert bigint to number: value exceeds the max safe integer value/) + assert.throws(function () { add(1, 123123123123123123123n) }, /Cannot implicitly convert bigint to number: value exceeds the max safe integer value/) + }) + it('should add BigNumbers', function () { assert.deepStrictEqual(add(new BigNumber(0.1), new BigNumber(0.2)), new BigNumber(0.3)) assert.deepStrictEqual(add(new BigNumber('2e5001'), new BigNumber('3e5000')), new BigNumber('2.3e5001')) @@ -47,6 +59,11 @@ describe('addScalar', function () { assert.throws(function () { add(new BigNumber(1), 1 / 3) }, /Cannot implicitly convert a number with >15 significant digits to BigNumber/) }) + it('should add mixed bigints and BigNumbers', function () { + assert.deepStrictEqual(add(new BigNumber(2), 3n), new BigNumber(5)) + assert.deepStrictEqual(add(2n, new BigNumber(3)), new BigNumber(5)) + }) + it('should add mixed booleans and BigNumbers', function () { assert.deepStrictEqual(add(new BigNumber(0.1), true), new BigNumber(1.1)) assert.deepStrictEqual(add(new BigNumber(0.1), false), new BigNumber(0.1)) @@ -54,6 +71,13 @@ describe('addScalar', function () { assert.deepStrictEqual(add(true, new BigNumber(0.2)), new math.BigNumber(1.2)) }) + it('should add mixed booleans and bigint', function () { + assert.deepStrictEqual(add(2n, true), 3n) + assert.deepStrictEqual(add(2n, false), 2n) + assert.deepStrictEqual(add(true, 2n), 3n) + assert.deepStrictEqual(add(false, 2n), 2n) + }) + it('should add mixed complex numbers and BigNumbers', function () { assert.deepStrictEqual(add(math.complex(3, -4), new BigNumber(2)), math.complex(5, -4)) assert.deepStrictEqual(add(new BigNumber(2), math.complex(3, -4)), math.complex(5, -4)) @@ -85,6 +109,11 @@ describe('addScalar', function () { assert.deepStrictEqual(add(math.fraction(1, 3), 1), math.fraction(4, 3)) }) + it('should add mixed fractions and bigints', function () { + assert.deepStrictEqual(add(1n, math.fraction(1, 3)), math.fraction(4, 3)) + assert.deepStrictEqual(add(math.fraction(1, 3), 1n), math.fraction(4, 3)) + }) + it('should throw an error when converting a number to a fraction that is not an exact representation', function () { assert.throws(function () { add(math.pi, math.fraction(1, 3)) diff --git a/test/unit-tests/function/arithmetic/cube.test.js b/test/unit-tests/function/arithmetic/cube.test.js index e93ba1a30e..a36a6e4fb8 100644 --- a/test/unit-tests/function/arithmetic/cube.test.js +++ b/test/unit-tests/function/arithmetic/cube.test.js @@ -19,6 +19,12 @@ describe('cube', function () { assert.strictEqual(cube(0), 0) }) + it('should return the cube of a bigint', function () { + assert.strictEqual(cube(4n), 64n) + assert.strictEqual(cube(-2n), -8n) + assert.strictEqual(cube(0n), 0n) + }) + it('should return the cube of a big number', function () { assert.deepStrictEqual(cube(bignumber(4)), bignumber(64)) assert.deepStrictEqual(cube(bignumber(-2)), bignumber(-8)) diff --git a/test/unit-tests/function/arithmetic/divide.test.js b/test/unit-tests/function/arithmetic/divide.test.js index 4333c3b7f1..e217e44fb2 100644 --- a/test/unit-tests/function/arithmetic/divide.test.js +++ b/test/unit-tests/function/arithmetic/divide.test.js @@ -19,6 +19,10 @@ describe('divide', function () { assert.ok(isNaN(divide(0, 0))) }) + it('should divide bigint', function () { + assert.strictEqual(divide(6n, 3n), 2n) + }) + it('should divide booleans', function () { assert.strictEqual(divide(true, true), 1) assert.strictEqual(divide(true, false), Infinity) @@ -33,6 +37,14 @@ describe('divide', function () { assert.strictEqual(divide(false, 2), 0) }) + it('should divide mixed numbers and bigint', function () { + assert.strictEqual(divide(6, 3n), 2) + assert.strictEqual(divide(6n, 3), 2) + + assert.throws(function () { divide(123123123123123123123n, 1) }, /Cannot implicitly convert bigint to number: value exceeds the max safe integer value/) + assert.throws(function () { divide(1, 123123123123123123123n) }, /Cannot implicitly convert bigint to number: value exceeds the max safe integer value/) + }) + it('should divide bignumbers', function () { assert.deepStrictEqual(divide(bignumber(0.3), bignumber(0.2)), bignumber(1.5)) assert.deepStrictEqual(divide(bignumber('2.6e5000'), bignumber('2')), bignumber('1.3e5000')) @@ -108,6 +120,11 @@ describe('divide', function () { assert.deepStrictEqual(divide(math.fraction(1), 3), math.fraction(1, 3)) }) + it('should divide mixed fractions and bigints', function () { + assert.deepStrictEqual(divide(1n, math.fraction(3)), math.fraction(1, 3)) + assert.deepStrictEqual(divide(math.fraction(1), 3n), math.fraction(1, 3)) + }) + it('should divide units by a number', function () { assert.strictEqual(divide(math.unit('5 m'), 10).toString(), '0.5 m') }) diff --git a/test/unit-tests/function/arithmetic/mod.test.js b/test/unit-tests/function/arithmetic/mod.test.js index 5146ddf233..5055a0f0b5 100644 --- a/test/unit-tests/function/arithmetic/mod.test.js +++ b/test/unit-tests/function/arithmetic/mod.test.js @@ -32,6 +32,20 @@ describe('mod', function () { approxEqual(mod(0, 3), 0) approxEqual(mod(-10, 4), 2) approxEqual(mod(-5, 3), 1) + approxEqual(mod(-7, 6), 5) + approxEqual(mod(-8, 4), 0) + }) + + it('should calculate the modulus of two bigints', function () { + assert.strictEqual(mod(1n, 1n), 0n) + assert.strictEqual(mod(0n, 1n), 0n) + assert.strictEqual(mod(1n, 0n), 1n) + assert.strictEqual(mod(0n, 0n), 0n) + assert.strictEqual(mod(7n, 0n), 7n) + assert.strictEqual(mod(-10, 4), 2) + assert.strictEqual(mod(-5n, 3n), 1n) + assert.strictEqual(mod(-7n, 6n), 5n) + assert.strictEqual(mod(-8n, 4n), 0n) }) it('should handle precise approximation of float approximation', function () { diff --git a/test/unit-tests/function/arithmetic/multiply.test.js b/test/unit-tests/function/arithmetic/multiply.test.js index 636c38ecd8..7aa2a8d419 100644 --- a/test/unit-tests/function/arithmetic/multiply.test.js +++ b/test/unit-tests/function/arithmetic/multiply.test.js @@ -24,6 +24,10 @@ describe('multiply', function () { approxDeepEqual(multiply(-2, Infinity), -Infinity) }) + it('should multiply bigint', function () { + assert.strictEqual(multiply(2n, 3n), 6n) + }) + it('should multiply booleans', function () { assert.strictEqual(multiply(true, true), 1) assert.strictEqual(multiply(true, false), 0) @@ -38,6 +42,14 @@ describe('multiply', function () { assert.strictEqual(multiply(false, 2), 0) }) + it('should multiply mixed numbers and bigint', function () { + assert.strictEqual(multiply(2, 3n), 6) + assert.strictEqual(multiply(2n, 3), 6) + + assert.throws(function () { multiply(123123123123123123123n, 1) }, /Cannot implicitly convert bigint to number: value exceeds the max safe integer value/) + assert.throws(function () { multiply(1, 123123123123123123123n) }, /Cannot implicitly convert bigint to number: value exceeds the max safe integer value/) + }) + it('should multiply bignumbers', function () { assert.deepStrictEqual(multiply(bignumber(1.5), bignumber(0.2)), bignumber(0.3)) assert.deepStrictEqual(multiply(bignumber('1.3e5000'), bignumber('2')), bignumber('2.6e5000')) @@ -52,6 +64,11 @@ describe('multiply', function () { assert.throws(function () { multiply(bignumber(1).div(3), 1 / 3) }, /Cannot implicitly convert a number with >15 significant digits to BigNumber/) }) + it('should multiply mixed bigints and BigNumbers', function () { + assert.deepStrictEqual(multiply(bignumber(2), 3n), bignumber(6)) + assert.deepStrictEqual(multiply(2n, bignumber(3)), bignumber(6)) + }) + it('should throw an error when multipling mixed fractions and bignumbers', function () { assert.throws(function () { multiply(math.bignumber('2'), math.fraction(1, 3)) }, /Cannot implicitly convert a Fraction to BigNumber/) assert.throws(function () { multiply(math.fraction(1, 3), math.bignumber('2')) }, /Cannot implicitly convert a Fraction to BigNumber/) @@ -134,6 +151,11 @@ describe('multiply', function () { assert.deepStrictEqual(multiply(math.fraction(1, 3), 2), math.fraction(2, 3)) }) + it('should multiply mixed fractions and bigints', function () { + assert.deepStrictEqual(multiply(2n, math.fraction(1, 3)), math.fraction(2, 3)) + assert.deepStrictEqual(multiply(math.fraction(1, 3), 2n), math.fraction(2, 3)) + }) + it('should multiply a number and a unit correctly', function () { assert.strictEqual(multiply(2, unit('5 mm')).toString(), '10 mm') assert.strictEqual(multiply(2, unit('5 mm')).toString(), '10 mm') @@ -160,6 +182,10 @@ describe('multiply', function () { assert.strictEqual(multiply(unit('inch'), 2).toString(), '2 inch') }) + it('should multiply a bigint and a unit value correctly', function () { + assert.strictEqual(multiply(2n, unit('5 mm')).toString(), '10 mm') + }) + it('should multiply two units correctly', function () { assert.strictEqual(multiply(unit('2 m'), unit('4 m')).toString(), '8 m^2') assert.strictEqual(multiply(unit('2 ft'), unit('4 ft')).toString(), '8 ft^2') diff --git a/test/unit-tests/function/arithmetic/pow.test.js b/test/unit-tests/function/arithmetic/pow.test.js index 923362b16f..df0d80ceb6 100644 --- a/test/unit-tests/function/arithmetic/pow.test.js +++ b/test/unit-tests/function/arithmetic/pow.test.js @@ -24,6 +24,14 @@ describe('pow', function () { approxDeepEqual(pow(2, 1.5), 2.82842712474619) }) + it('should exponentiate a bigint to the given power', function () { + assert.strictEqual(pow(2n, 3n), 8n) + assert.strictEqual(pow(2n, 4n), 16n) + assert.strictEqual(pow(-2n, 2n), 4n) + assert.strictEqual(pow(3n, 3n), 27n) + assert.throws(() => pow(3n, -2n)) + }) + it('should exponentiate a negative number to a non-integer power', function () { approxDeepEqual(pow(-2, 1.5), complex(0, -2.82842712474619)) approxDeepEqual(pow(-8, 1 / 3), complex(1, 1.732050807568877)) diff --git a/test/unit-tests/function/arithmetic/sign.test.js b/test/unit-tests/function/arithmetic/sign.test.js index b569c7cffb..17a620f8bd 100644 --- a/test/unit-tests/function/arithmetic/sign.test.js +++ b/test/unit-tests/function/arithmetic/sign.test.js @@ -19,6 +19,12 @@ describe('sign', function () { assert.strictEqual(math.sign(0), 0) }) + it('should calculate the sign of a bigint', function () { + assert.strictEqual(math.sign(3n), 1n) + assert.strictEqual(math.sign(-3n), -1n) + assert.strictEqual(math.sign(0n), 0n) + }) + it('should calculate the sign of a big number', function () { assert.deepStrictEqual(math.sign(bignumber(3)), bignumber(1)) assert.deepStrictEqual(math.sign(bignumber(-3)), bignumber(-1)) diff --git a/test/unit-tests/function/arithmetic/square.test.js b/test/unit-tests/function/arithmetic/square.test.js index f3b34c50fb..a6a9f5cce2 100644 --- a/test/unit-tests/function/arithmetic/square.test.js +++ b/test/unit-tests/function/arithmetic/square.test.js @@ -19,6 +19,12 @@ describe('square', function () { assert.strictEqual(square(0), 0) }) + it('should return the square of a bigint', function () { + assert.strictEqual(square(4n), 16n) + assert.strictEqual(square(-2n), 4n) + assert.strictEqual(square(0n), 0n) + }) + it('should return the square of a big number', function () { assert.deepStrictEqual(square(bignumber(4)), bignumber(16)) assert.deepStrictEqual(square(bignumber(-2)), bignumber(4)) diff --git a/test/unit-tests/function/arithmetic/subtractScalar.test.js b/test/unit-tests/function/arithmetic/subtractScalar.test.js index 994201cdf5..b692c386f1 100644 --- a/test/unit-tests/function/arithmetic/subtractScalar.test.js +++ b/test/unit-tests/function/arithmetic/subtractScalar.test.js @@ -19,6 +19,10 @@ describe('subtractScalar', function () { assert.deepStrictEqual(subtractScalar(0, 3), -3) }) + it('should subtractScalar bigint', function () { + assert.strictEqual(subtractScalar(7n, 3n), 4n) + }) + it('should subtractScalar booleans', function () { assert.strictEqual(subtractScalar(true, true), 0) assert.strictEqual(subtractScalar(true, false), 1) @@ -33,6 +37,14 @@ describe('subtractScalar', function () { assert.strictEqual(subtractScalar(false, 2), -2) }) + it('should subtractScalar mixed numbers and bigint', function () { + assert.strictEqual(subtractScalar(7, 3n), 4) + assert.strictEqual(subtractScalar(7n, 3), 4) + + assert.throws(function () { subtractScalar(123123123123123123123n, 1) }, /Cannot implicitly convert bigint to number: value exceeds the max safe integer value/) + assert.throws(function () { subtractScalar(1, 123123123123123123123n) }, /Cannot implicitly convert bigint to number: value exceeds the max safe integer value/) + }) + it('should subtractScalar new BigNumbers', function () { assert.deepStrictEqual(subtractScalar(new BigNumber(0.3), new BigNumber(0.2)), new BigNumber(0.1)) assert.deepStrictEqual(subtractScalar(new BigNumber('2.3e5001'), new BigNumber('3e5000')), new BigNumber('2e5001')) @@ -47,6 +59,11 @@ describe('subtractScalar', function () { assert.throws(function () { subtractScalar(new BigNumber(1).div(3), 1 / 3) }, /Cannot implicitly convert a number with >15 significant digits to BigNumber/) }) + it('should subtractScalar mixed bigints and BigNumbers', function () { + assert.deepStrictEqual(subtractScalar(new BigNumber(7), 3n), new BigNumber(4)) + assert.deepStrictEqual(subtractScalar(7n, new BigNumber(3)), new BigNumber(4)) + }) + it('should add Decimals', function () { assert.deepStrictEqual(subtractScalar(Decimal(0.2), Decimal(0.1)), Decimal(0.1)) assert.deepStrictEqual(subtractScalar(Decimal(0.3), 0.2), Decimal(0.1)) @@ -92,6 +109,11 @@ describe('subtractScalar', function () { assert.deepStrictEqual(subtractScalar(math.fraction(1, 3), 1), math.fraction(-2, 3)) }) + it('should subtractScalar mixed fractions and numbers', function () { + assert.deepStrictEqual(subtractScalar(1n, math.fraction(1, 3)), math.fraction(2, 3)) + assert.deepStrictEqual(subtractScalar(math.fraction(1, 3), 1n), math.fraction(-2, 3)) + }) + it('should subtractScalar two quantities of the same unit', function () { approxDeepEqual(subtractScalar(math.unit(5, 'km'), math.unit(100, 'mile')), math.unit(-155.93, 'km')) diff --git a/test/unit-tests/function/arithmetic/unaryMinus.test.js b/test/unit-tests/function/arithmetic/unaryMinus.test.js index ebb6ccc29d..895091e290 100644 --- a/test/unit-tests/function/arithmetic/unaryMinus.test.js +++ b/test/unit-tests/function/arithmetic/unaryMinus.test.js @@ -26,6 +26,12 @@ describe('unaryMinus', function () { assert.deepStrictEqual(math.unaryMinus(0), -0) }) + it('should perform unary minus of a bigint', function () { + assert.deepStrictEqual(math.unaryMinus(2n), -2n) + assert.deepStrictEqual(math.unaryMinus(-2n), 2n) + assert.deepStrictEqual(math.unaryMinus(0n), -0n) + }) + it('should perform unary minus of a big number', function () { assert.deepStrictEqual(math.unaryMinus(bignumber(2)), bignumber(-2)) assert.deepStrictEqual(math.unaryMinus(bignumber(-2)), bignumber(2)) diff --git a/test/unit-tests/function/arithmetic/unaryPlus.test.js b/test/unit-tests/function/arithmetic/unaryPlus.test.js index 49fc9cf261..c020308998 100644 --- a/test/unit-tests/function/arithmetic/unaryPlus.test.js +++ b/test/unit-tests/function/arithmetic/unaryPlus.test.js @@ -24,8 +24,17 @@ describe('unaryPlus', function () { it('should return bignumber unary plus on a string', function () { const bigmath = math.create({ number: 'BigNumber' }) - assert.deepStrictEqual(bigmath.unaryPlus('2'), bigmath.bignumber(2)) - assert.deepStrictEqual(bigmath.unaryPlus('-2'), bigmath.bignumber(-2)) + assert.deepStrictEqual(bigmath.unaryPlus('20000000000000000000001'), bigmath.bignumber('20000000000000000000001')) + assert.deepStrictEqual(bigmath.unaryPlus('-20000000000000000000001'), bigmath.bignumber('-20000000000000000000001')) + }) + + it('should return bigint unary plus on a string', function () { + const bigmath = math.create({ number: 'bigint' }) + assert.deepStrictEqual(bigmath.unaryPlus('20000000000000000000001'), 20000000000000000000001n) + assert.deepStrictEqual(bigmath.unaryPlus('-20000000000000000000001'), -20000000000000000000001n) + assert.deepStrictEqual(bigmath.unaryPlus('2.4'), 2.4) // fallback to number + assert.deepStrictEqual(bigmath.unaryPlus(true), 1n) + assert.deepStrictEqual(bigmath.unaryPlus(false), 0n) }) // TODO: this is temporary until the test above works again @@ -46,6 +55,12 @@ describe('unaryPlus', function () { assert.deepStrictEqual(math.unaryPlus(0), 0) }) + it('should perform unary plus of a bigint', function () { + assert.deepStrictEqual(math.unaryPlus(2n), 2n) + assert.deepStrictEqual(math.unaryPlus(-2n), -2n) + assert.deepStrictEqual(math.unaryPlus(0n), 0n) + }) + it('should perform unary plus of a big number', function () { assert.deepStrictEqual(math.unaryPlus(bignumber(2)), bignumber(2)) assert.deepStrictEqual(math.unaryPlus(bignumber(-2)), bignumber(-2)) diff --git a/test/unit-tests/function/bitwise/bitAnd.test.js b/test/unit-tests/function/bitwise/bitAnd.test.js index 07ebc9d64e..9f1bee44e0 100644 --- a/test/unit-tests/function/bitwise/bitAnd.test.js +++ b/test/unit-tests/function/bitwise/bitAnd.test.js @@ -14,6 +14,14 @@ describe('bitAnd', function () { assert.strictEqual(bitAnd(-5, -3), -7) }) + it('should bitwise and two bigints', function () { + assert.strictEqual(bitAnd(53n, 131n), 1n) + assert.strictEqual(bitAnd(2n, 3n), 2n) + assert.strictEqual(bitAnd(-2n, 3n), 2n) + assert.strictEqual(bitAnd(2n, -3n), 0n) + assert.strictEqual(bitAnd(-5n, -3n), -7n) + }) + it('should bitwise and booleans', function () { assert.strictEqual(bitAnd(true, true), 1) assert.strictEqual(bitAnd(true, false), 0) @@ -44,6 +52,11 @@ describe('bitAnd', function () { assert.deepStrictEqual(bitAnd(7, bignumber(9)), bignumber(1)) }) + it('should bitwise and mixed numbers and bigints', function () { + assert.strictEqual(bitAnd(53n, 131), 1) + assert.strictEqual(bitAnd(53, 131n), 1) + }) + it('should bitwise and mixed booleans and bignumbers', function () { assert.deepStrictEqual(bitAnd(bignumber(1), true), bignumber(1)) assert.deepStrictEqual(bitAnd(bignumber(1), false), bignumber(0)) diff --git a/test/unit-tests/function/bitwise/bitNot.test.js b/test/unit-tests/function/bitwise/bitNot.test.js index 10a99b99ab..aac3dea4f4 100644 --- a/test/unit-tests/function/bitwise/bitNot.test.js +++ b/test/unit-tests/function/bitwise/bitNot.test.js @@ -17,6 +17,12 @@ describe('bitNot', function () { assert.deepStrictEqual(bitNot(0), -1) }) + it('should perform bitwise not of a bigint', function () { + assert.deepStrictEqual(bitNot(2n), -3n) + assert.deepStrictEqual(bitNot(-2n), 1n) + assert.deepStrictEqual(bitNot(0n), -1n) + }) + it('should perform bitwise not of a bignumber', function () { assert.deepStrictEqual(bitNot(bignumber(2)), bignumber(-3)) assert.deepStrictEqual(bitNot(bignumber(-2)), bignumber(1)) diff --git a/test/unit-tests/function/bitwise/bitOr.test.js b/test/unit-tests/function/bitwise/bitOr.test.js index c3e0f3cb98..d0a9aa27f7 100644 --- a/test/unit-tests/function/bitwise/bitOr.test.js +++ b/test/unit-tests/function/bitwise/bitOr.test.js @@ -14,6 +14,14 @@ describe('bitOr', function () { assert.strictEqual(bitOr(-5, -3), -1) }) + it('should bitwise or two bigints', function () { + assert.strictEqual(bitOr(53n, 131n), 183n) + assert.strictEqual(bitOr(2n, 3n), 3n) + assert.strictEqual(bitOr(-2n, 3n), -1n) + assert.strictEqual(bitOr(2n, -3n), -1n) + assert.strictEqual(bitOr(-5n, -3n), -1n) + }) + it('should bitwise or booleans', function () { assert.strictEqual(bitOr(true, true), 1) assert.strictEqual(bitOr(true, false), 1) @@ -43,6 +51,11 @@ describe('bitOr', function () { assert.deepStrictEqual(bitOr(7, bignumber(9)), bignumber(15)) }) + it('should bitwise or mixed numbers and bigints', function () { + assert.strictEqual(bitOr(53, 131n), 183) + assert.strictEqual(bitOr(53n, 131), 183) + }) + it('should bitwise or mixed booleans and bignumbers', function () { assert.deepStrictEqual(bitOr(bignumber(1), false), bignumber(1)) assert.deepStrictEqual(bitOr(bignumber(2), true), bignumber(3)) diff --git a/test/unit-tests/function/bitwise/bitXor.test.js b/test/unit-tests/function/bitwise/bitXor.test.js index 17ec7c26d5..516e56a51d 100644 --- a/test/unit-tests/function/bitwise/bitXor.test.js +++ b/test/unit-tests/function/bitwise/bitXor.test.js @@ -16,6 +16,14 @@ describe('bitXor', function () { assert.strictEqual(bitXor(-5, -3), 6) }) + it('should xor two bigints', function () { + assert.strictEqual(bitXor(53n, 131n), 182n) + assert.strictEqual(bitXor(2n, 3n), 1n) + assert.strictEqual(bitXor(-2n, 3n), -3n) + assert.strictEqual(bitXor(2n, -3n), -1n) + assert.strictEqual(bitXor(-5n, -3n), 6n) + }) + it('should xor booleans', function () { assert.strictEqual(bitXor(true, true), 0) assert.strictEqual(bitXor(true, false), 1) @@ -47,6 +55,11 @@ describe('bitXor', function () { assert.deepStrictEqual(bitXor(7, bignumber(9)), bignumber(14)) }) + it('should bitwise xor mixed numbers and bigints', function () { + assert.strictEqual(bitXor(53n, 131), 182) + assert.strictEqual(bitXor(53, 131n), 182) + }) + it('should bitwise xor mixed booleans and bignumbers', function () { assert.deepStrictEqual(bitXor(bignumber(1), true), bignumber(0)) assert.deepStrictEqual(bitXor(bignumber(1), false), bignumber(1)) diff --git a/test/unit-tests/function/bitwise/leftShift.test.js b/test/unit-tests/function/bitwise/leftShift.test.js index 659ab9a6bd..321d701438 100644 --- a/test/unit-tests/function/bitwise/leftShift.test.js +++ b/test/unit-tests/function/bitwise/leftShift.test.js @@ -19,6 +19,17 @@ describe('leftShift', function () { assert.strictEqual(leftShift(-3, 3), -24) }) + it('should left shift a bigint by a given amount', function () { + assert.strictEqual(leftShift(0n, 1000n), 0n) + assert.strictEqual(leftShift(2n, 0n), 2n) + assert.strictEqual(leftShift(2n, 3n), 16n) + assert.strictEqual(leftShift(2n, 4n), 32n) + assert.strictEqual(leftShift(-2n, 2n), -8n) + assert.strictEqual(leftShift(3n, 3n), 24n) + assert.strictEqual(leftShift(-3n, 2n), -12n) + assert.strictEqual(leftShift(-3n, 3n), -24n) + }) + it('should left shift booleans by a boolean amount', function () { assert.strictEqual(leftShift(true, true), 2) assert.strictEqual(leftShift(true, false), 1) @@ -33,6 +44,11 @@ describe('leftShift', function () { assert.strictEqual(leftShift(false, 2), 0) }) + it('should left shift with a mix of numbers and bigints', function () { + assert.strictEqual(leftShift(2, 3n), 16) + assert.strictEqual(leftShift(2n, 3), 16) + }) + it('should left shift bignumbers', function () { assert.deepStrictEqual(leftShift(bignumber(2), bignumber(3)), bignumber(16)) assert.deepStrictEqual(leftShift(bignumber(500), bignumber(100)), bignumber('633825300114114700748351602688000')) diff --git a/test/unit-tests/function/bitwise/rightArithShift.test.js b/test/unit-tests/function/bitwise/rightArithShift.test.js index d8b24cc159..37cd4fd047 100644 --- a/test/unit-tests/function/bitwise/rightArithShift.test.js +++ b/test/unit-tests/function/bitwise/rightArithShift.test.js @@ -20,6 +20,18 @@ describe('rightArithShift', function () { assert.strictEqual(rightArithShift(-13, 3), -2) }) + it('should right arithmetically shift a bigint by a given amount', function () { + assert.strictEqual(rightArithShift(0n, 1000n), 0n) + assert.strictEqual(rightArithShift(2n, 0n), 2n) + assert.strictEqual(rightArithShift(12n, 3n), 1n) + assert.strictEqual(rightArithShift(32n, 4n), 2n) + assert.strictEqual(rightArithShift(-1n, 1000n), -1n) + assert.strictEqual(rightArithShift(-12n, 2n), -3n) + assert.strictEqual(rightArithShift(122n, 3n), 15n) + assert.strictEqual(rightArithShift(-13n, 2n), -4n) + assert.strictEqual(rightArithShift(-13n, 3n), -2n) + }) + it('should right arithmetically shift booleans by a boolean amount', function () { assert.strictEqual(rightArithShift(true, true), 0) assert.strictEqual(rightArithShift(true, false), 1) @@ -35,6 +47,11 @@ describe('rightArithShift', function () { assert.strictEqual(rightArithShift(false, 2), 0) }) + it('should right arithmetically shift with a mix of numbers and bigints', function () { + assert.strictEqual(rightArithShift(122, 3n), 15) + assert.strictEqual(rightArithShift(122n, 3), 15) + }) + it('should right arithmetically shift bignumbers', function () { assert.deepStrictEqual(rightArithShift(bignumber(17), bignumber(3)), bignumber(2)) assert.deepStrictEqual(rightArithShift(bignumber('633825300114114700748351602688000'), bignumber(100)), bignumber(500)) diff --git a/test/unit-tests/function/logical/and.test.js b/test/unit-tests/function/logical/and.test.js index 6253777ce2..051a838fed 100644 --- a/test/unit-tests/function/logical/and.test.js +++ b/test/unit-tests/function/logical/and.test.js @@ -82,6 +82,14 @@ describe('and', function () { assert.strictEqual(and(bignumber(Infinity), bignumber(-Infinity)), true) }) + it('should and bigints', function () { + assert.strictEqual(and(1n, 1n), true) + assert.strictEqual(and(-1n, 1n), true) + assert.strictEqual(and(-1n, -1n), true) + assert.strictEqual(and(0n, -1n), false) + assert.strictEqual(and(1n, 0n), false) + }) + it('should and mixed numbers and bignumbers', function () { assert.strictEqual(and(bignumber(2), 3), true) assert.strictEqual(and(2, bignumber(2)), true) @@ -91,6 +99,15 @@ describe('and', function () { assert.strictEqual(and(bignumber(2), 0), false) }) + it('should and mixed numbers and bigints', function () { + assert.strictEqual(and(2n, 3), true) + assert.strictEqual(and(2, 2n), true) + assert.strictEqual(and(0, 2n), false) + assert.strictEqual(and(2, 0n), false) + assert.strictEqual(and(0n, 2), false) + assert.strictEqual(and(2n, 0), false) + }) + it('should and two units', function () { assert.strictEqual(and(unit('100cm'), unit('10inch')), true) assert.strictEqual(and(unit('100cm'), unit('0 inch')), false) diff --git a/test/unit-tests/function/logical/not.test.js b/test/unit-tests/function/logical/not.test.js index c946a56263..f4a39653e0 100644 --- a/test/unit-tests/function/logical/not.test.js +++ b/test/unit-tests/function/logical/not.test.js @@ -24,6 +24,12 @@ describe('not', function () { assert.strictEqual(not(NaN), true) }) + it('should not a bigint', function () { + assert.strictEqual(not(1n), false) + assert.strictEqual(not(-1n), false) + assert.strictEqual(not(0n), true) + }) + it('should not complex numbers', function () { assert.strictEqual(not(complex(1, 1)), false) assert.strictEqual(not(complex(0, 1)), false) diff --git a/test/unit-tests/function/logical/or.test.js b/test/unit-tests/function/logical/or.test.js index 0b032cf32f..6df8c8225e 100644 --- a/test/unit-tests/function/logical/or.test.js +++ b/test/unit-tests/function/logical/or.test.js @@ -96,6 +96,14 @@ describe('or', function () { assert.strictEqual(or(bignumber(0), bignumber(0)), false) }) + it('should or bigints', function () { + assert.strictEqual(or(1n, 1n), true) + assert.strictEqual(or(-1n, 1n), true) + assert.strictEqual(or(-1n, -1n), true) + assert.strictEqual(or(0n, -1n), true) + assert.strictEqual(or(1n, 0n), true) + }) + it('should or mixed numbers and bignumbers', function () { assert.strictEqual(or(bignumber(2), 3), true) assert.strictEqual(or(2, bignumber(2)), true) @@ -107,6 +115,11 @@ describe('or', function () { assert.strictEqual(or(bignumber(0), 0), false) }) + it('should or mixed numbers and bigints', function () { + assert.strictEqual(or(2n, 3), true) + assert.strictEqual(or(2, 3n), true) + }) + it('should or two units', function () { assert.strictEqual(or(unit('100cm'), unit('10inch')), true) assert.strictEqual(or(unit('100cm'), unit('0 inch')), true) diff --git a/test/unit-tests/function/logical/xor.test.js b/test/unit-tests/function/logical/xor.test.js index 3929e79e90..fd95931e4a 100644 --- a/test/unit-tests/function/logical/xor.test.js +++ b/test/unit-tests/function/logical/xor.test.js @@ -95,6 +95,14 @@ describe('xor', function () { assert.strictEqual(xor(bignumber(0), bignumber(0)), false) }) + it('should xor bigints', function () { + assert.strictEqual(xor(1n, 1n), false) + assert.strictEqual(xor(-1n, 1n), false) + assert.strictEqual(xor(-1n, -1n), false) + assert.strictEqual(xor(0n, -1n), true) + assert.strictEqual(xor(1n, 0n), true) + }) + it('should xor mixed numbers and bignumbers', function () { assert.strictEqual(xor(bignumber(2), 3), false) assert.strictEqual(xor(2, bignumber(2)), false) @@ -105,6 +113,11 @@ describe('xor', function () { assert.strictEqual(xor(bignumber(0), 0), false) }) + it('should xor mixed numbers and bigints', function () { + assert.strictEqual(xor(2n, 3), false) + assert.strictEqual(xor(0, 2n), true) + }) + it('should xor two units', function () { assert.strictEqual(xor(unit('100cm'), unit('10inch')), false) assert.strictEqual(xor(unit('100cm'), unit('0 inch')), true) diff --git a/test/unit-tests/function/relational/compare.test.js b/test/unit-tests/function/relational/compare.test.js index aee6b369df..9439a6f849 100644 --- a/test/unit-tests/function/relational/compare.test.js +++ b/test/unit-tests/function/relational/compare.test.js @@ -20,6 +20,16 @@ describe('compare', function () { assert.strictEqual(compare(-3, -2), -1) }) + it('should compare two bigints correctly', function () { + assert.strictEqual(compare(2n, 3n), -1n) + assert.strictEqual(compare(2n, 2n), 0n) + assert.strictEqual(compare(2n, 1n), 1n) + assert.strictEqual(compare(0n, 0n), 0n) + assert.strictEqual(compare(-2n, 2n), -1n) + assert.strictEqual(compare(-2n, -3n), 1n) + assert.strictEqual(compare(-3n, -2n), -1n) + }) + it('should compare two floating point numbers correctly', function () { // Infinity assert.strictEqual(compare(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY), 0) @@ -61,6 +71,16 @@ describe('compare', function () { assert.deepStrictEqual(compare(2, bignumber(2)), bignumber(0)) }) + it('should compare mixed numbers and bigints', function () { + assert.deepStrictEqual(compare(2n, 3), -1) + assert.deepStrictEqual(compare(2, 2n), 0) + }) + + it('should compare mixed bigints and bignumbers', function () { + assert.deepStrictEqual(compare(bignumber(2), 3n), bignumber(-1)) + assert.deepStrictEqual(compare(2n, bignumber(2)), bignumber(0)) + }) + it('should compare mixed booleans and bignumbers', function () { assert.deepStrictEqual(compare(bignumber(0.1), true), bignumber(-1)) assert.deepStrictEqual(compare(bignumber(1), true), bignumber(0)) @@ -88,6 +108,11 @@ describe('compare', function () { assert.deepStrictEqual(compare(math.fraction(1, 3), 1), math.fraction(-1)) }) + it('should compare mixed fractions and bigints', function () { + assert.deepStrictEqual(compare(1n, math.fraction(1, 3)), math.fraction(1)) + assert.deepStrictEqual(compare(math.fraction(1, 3), 1n), math.fraction(-1)) + }) + it('should add two measures of the same unit', function () { assert.strictEqual(compare(unit('100cm'), unit('10inch')), 1) assert.strictEqual(compare(unit('99cm'), unit('1m')), -1) diff --git a/test/unit-tests/function/relational/equal.test.js b/test/unit-tests/function/relational/equal.test.js index 16a037011a..73eb1dd90f 100644 --- a/test/unit-tests/function/relational/equal.test.js +++ b/test/unit-tests/function/relational/equal.test.js @@ -17,6 +17,13 @@ describe('equal', function () { assert.strictEqual(equal(-2, 2), false) }) + it('should compare two bigints correctly', function () { + assert.strictEqual(equal(2n, 3n), false) + assert.strictEqual(equal(2n, 2n), true) + assert.strictEqual(equal(0n, 0n), true) + assert.strictEqual(equal(-2n, 2n), false) + }) + it('should compare two floating point numbers correctly', function () { // NaN assert.strictEqual(equal(Number.NaN, Number.NaN), false) @@ -70,6 +77,14 @@ describe('equal', function () { assert.throws(function () { equal(bignumber(1).div(3), 1 / 3) }, /Cannot implicitly convert a number with >15 significant digits to BigNumber/) }) + it('should compare mixed numbers and bigint', function () { + assert.deepStrictEqual(equal(2n, 3), false) + assert.deepStrictEqual(equal(2, 2n), true) + + assert.throws(function () { equal(123123123123123123123n, 1) }, /Cannot implicitly convert bigint to number: value exceeds the max safe integer value/) + assert.throws(function () { equal(1, 123123123123123123123n) }, /Cannot implicitly convert bigint to number: value exceeds the max safe integer value/) + }) + it('should compare mixed booleans and bignumbers', function () { assert.strictEqual(equal(bignumber(0.1), true), false) assert.strictEqual(equal(bignumber(1), true), true) diff --git a/test/unit-tests/function/relational/larger.test.js b/test/unit-tests/function/relational/larger.test.js index 813643eba0..7523bf2c5d 100644 --- a/test/unit-tests/function/relational/larger.test.js +++ b/test/unit-tests/function/relational/larger.test.js @@ -20,6 +20,16 @@ describe('larger', function () { assert.strictEqual(larger(-3, -2), false) }) + it('should compare two bigints correctly', function () { + assert.strictEqual(larger(2n, 3n), false) + assert.strictEqual(larger(2n, 2n), false) + assert.strictEqual(larger(2n, 1n), true) + assert.strictEqual(larger(0n, 0n), false) + assert.strictEqual(larger(-2n, 2n), false) + assert.strictEqual(larger(-2n, -3n), true) + assert.strictEqual(larger(-3n, -2n), false) + }) + it('should compare two floating point numbers correctly', function () { // Infinity assert.strictEqual(larger(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY), false) @@ -64,6 +74,17 @@ describe('larger', function () { assert.throws(function () { larger(bignumber(1).div(3), 1 / 3) }, /Cannot implicitly convert a number with >15 significant digits to BigNumber/) }) + it('should compare mixed numbers and bigints', function () { + assert.strictEqual(larger(2n, 3), false) + assert.strictEqual(larger(2, 2n), false) + + assert.throws(function () { larger(1 / 3, bignumber(1).div(3)) }, /Cannot implicitly convert a number with >15 significant digits to BigNumber/) + assert.throws(function () { larger(bignumber(1).div(3), 1 / 3) }, /Cannot implicitly convert a number with >15 significant digits to BigNumber/) + + assert.throws(function () { larger(123123123123123123123n, 1) }, /Cannot implicitly convert bigint to number: value exceeds the max safe integer value/) + assert.throws(function () { larger(1, 123123123123123123123n) }, /Cannot implicitly convert bigint to number: value exceeds the max safe integer value/) + }) + it('should compare mixed booleans and bignumbers', function () { assert.strictEqual(larger(bignumber(0.1), true), false) assert.strictEqual(larger(bignumber(1), true), false) @@ -83,6 +104,11 @@ describe('larger', function () { assert.strictEqual(larger(math.fraction(2), 2), false) }) + it('should compare mixed fractions and bigints', function () { + assert.strictEqual(larger(1n, math.fraction(1, 3)), true) + assert.strictEqual(larger(math.fraction(2), 2n), false) + }) + it('should add two measures of the same unit', function () { assert.strictEqual(larger(unit('100cm'), unit('10inch')), true) assert.strictEqual(larger(unit('99cm'), unit('1m')), false) diff --git a/test/unit-tests/function/relational/largerEq.test.js b/test/unit-tests/function/relational/largerEq.test.js index 4213a278cf..42c8d4dd8b 100644 --- a/test/unit-tests/function/relational/largerEq.test.js +++ b/test/unit-tests/function/relational/largerEq.test.js @@ -20,6 +20,16 @@ describe('largerEq', function () { assert.strictEqual(largerEq(-3, -2), false) }) + it('should compare two bigints correctly', function () { + assert.strictEqual(largerEq(2n, 3n), false) + assert.strictEqual(largerEq(2n, 2n), true) + assert.strictEqual(largerEq(2n, 1n), true) + assert.strictEqual(largerEq(0n, 0n), true) + assert.strictEqual(largerEq(-2n, 2n), false) + assert.strictEqual(largerEq(-2n, -3n), true) + assert.strictEqual(largerEq(-3n, -2n), false) + }) + it('should compare two floating point numbers correctly', function () { // Infinity assert.strictEqual(largerEq(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY), true) @@ -65,6 +75,14 @@ describe('largerEq', function () { assert.throws(function () { largerEq(bignumber(1).div(3), 1 / 3) }, /TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber/) }) + it('should compare mixed numbers and bigints', function () { + assert.strictEqual(largerEq(2n, 3), false) + assert.strictEqual(largerEq(2, 2n), true) + + assert.throws(function () { largerEq(123123123123123123123n, 1) }, /Cannot implicitly convert bigint to number: value exceeds the max safe integer value/) + assert.throws(function () { largerEq(1, 123123123123123123123n) }, /Cannot implicitly convert bigint to number: value exceeds the max safe integer value/) + }) + it('should compare mixed booleans and bignumbers', function () { assert.strictEqual(largerEq(bignumber(0.1), true), false) assert.strictEqual(largerEq(bignumber(1), true), true) @@ -85,6 +103,11 @@ describe('largerEq', function () { assert.strictEqual(largerEq(math.fraction(2), 2), true) }) + it('should compare mixed fractions and bigints', function () { + assert.strictEqual(largerEq(1n, math.fraction(1, 3)), true) + assert.strictEqual(largerEq(math.fraction(2), 2n), true) + }) + it('should compare two units correctly', function () { assert.strictEqual(largerEq(unit('100cm'), unit('10inch')), true) assert.strictEqual(largerEq(unit('99cm'), unit('1m')), false) diff --git a/test/unit-tests/function/relational/smaller.test.js b/test/unit-tests/function/relational/smaller.test.js index a1fa9932b4..bdd271cbbe 100644 --- a/test/unit-tests/function/relational/smaller.test.js +++ b/test/unit-tests/function/relational/smaller.test.js @@ -20,6 +20,16 @@ describe('smaller', function () { assert.strictEqual(smaller(-3, -2), true) }) + it('should compare two bigints correctly', function () { + assert.strictEqual(smaller(2n, 3n), true) + assert.strictEqual(smaller(2n, 2n), false) + assert.strictEqual(smaller(2n, 1n), false) + assert.strictEqual(smaller(0n, 0n), false) + assert.strictEqual(smaller(-2n, 2n), true) + assert.strictEqual(smaller(-2n, -3n), false) + assert.strictEqual(smaller(-3n, -2n), true) + }) + it('should compare two floating point numbers correctly', function () { // Infinity assert.strictEqual(smaller(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY), false) @@ -69,6 +79,14 @@ describe('smaller', function () { assert.throws(function () { smaller(bignumber(1).div(3), 1 / 3) }, /Cannot implicitly convert a number with >15 significant digits to BigNumber/) }) + it('should compare mixed numbers and bigints', function () { + assert.deepStrictEqual(smaller(2n, 3), true) + assert.deepStrictEqual(smaller(2, 2n), false) + + assert.throws(function () { smaller(123123123123123123123n, 1) }, /Cannot implicitly convert bigint to number: value exceeds the max safe integer value/) + assert.throws(function () { smaller(1, 123123123123123123123n) }, /Cannot implicitly convert bigint to number: value exceeds the max safe integer value/) + }) + it('should compare mixed booleans and bignumbers', function () { assert.deepStrictEqual(smaller(bignumber(0.1), true), true) assert.deepStrictEqual(smaller(bignumber(1), true), false) @@ -90,6 +108,11 @@ describe('smaller', function () { assert.strictEqual(smaller(math.fraction(2), 2), false) }) + it('should compare mixed fractions and bigints', function () { + assert.strictEqual(smaller(1n, math.fraction(1, 3)), false) + assert.strictEqual(smaller(math.fraction(2), 2n), false) + }) + it('should compare two measures of the same unit correctly', function () { assert.strictEqual(smaller(unit('100cm'), unit('10inch')), false) assert.strictEqual(smaller(unit('99cm'), unit('1m')), true) diff --git a/test/unit-tests/function/relational/smallerEq.test.js b/test/unit-tests/function/relational/smallerEq.test.js index e3d43e47fd..2346ebed31 100644 --- a/test/unit-tests/function/relational/smallerEq.test.js +++ b/test/unit-tests/function/relational/smallerEq.test.js @@ -21,6 +21,17 @@ describe('smallerEq', function () { assert.strictEqual(smallerEq(-3, -2), true) }) + it('should compare two numbers correctly', function () { + assert.strictEqual(smallerEq(2n, 3n), true) + assert.strictEqual(smallerEq(2n, 2n), true) + assert.strictEqual(smallerEq(2n, 1n), false) + assert.strictEqual(smallerEq(0n, 0n), true) + assert.strictEqual(smallerEq(-2n, 2n), true) + assert.strictEqual(smallerEq(-2n, -3n), false) + assert.strictEqual(smallerEq(-2n, -2n), true) + assert.strictEqual(smallerEq(-3n, -2n), true) + }) + it('should compare two floating point numbers correctly', function () { // Infinity assert.strictEqual(smallerEq(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY), true) @@ -67,6 +78,14 @@ describe('smallerEq', function () { assert.throws(function () { smallerEq(bignumber(1).div(3), 1 / 3) }, /TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber/) }) + it('should compare mixed numbers and bigints', function () { + assert.deepStrictEqual(smallerEq(2n, 3), true) + assert.deepStrictEqual(smallerEq(2, 2n), true) + + assert.throws(function () { smallerEq(123123123123123123123n, 1) }, /Cannot implicitly convert bigint to number: value exceeds the max safe integer value/) + assert.throws(function () { smallerEq(1, 123123123123123123123n) }, /Cannot implicitly convert bigint to number: value exceeds the max safe integer value/) + }) + it('should compare mixed booleans and bignumbers', function () { assert.deepStrictEqual(smallerEq(bignumber(0.1), true), true) assert.deepStrictEqual(smallerEq(bignumber(1), true), true) @@ -88,6 +107,11 @@ describe('smallerEq', function () { assert.strictEqual(smallerEq(math.fraction(2), 2), true) }) + it('should compare mixed fractions and bigints', function () { + assert.strictEqual(smallerEq(1n, math.fraction(1, 3)), false) + assert.strictEqual(smallerEq(math.fraction(2), 2n), true) + }) + it('should compare two measures of the same unit correctly', function () { assert.strictEqual(smallerEq(unit('100cm'), unit('10inch')), false) assert.strictEqual(smallerEq(unit('99cm'), unit('1m')), true) diff --git a/test/unit-tests/function/relational/unequal.test.js b/test/unit-tests/function/relational/unequal.test.js index d00b58c20b..883c98b197 100644 --- a/test/unit-tests/function/relational/unequal.test.js +++ b/test/unit-tests/function/relational/unequal.test.js @@ -18,6 +18,14 @@ describe('unequal', function () { assert.strictEqual(unequal(true, 1), false) }) + it('should compare two bigints correctly', function () { + assert.strictEqual(unequal(2n, 3n), true) + assert.strictEqual(unequal(2n, 2n), false) + assert.strictEqual(unequal(0n, 0n), false) + assert.strictEqual(unequal(-2n, 2n), true) + assert.strictEqual(unequal(true, 1n), false) + }) + it('should compare two floating point numbers correctly', function () { // NaN assert.strictEqual(unequal(Number.NaN, Number.NaN), true) @@ -71,6 +79,14 @@ describe('unequal', function () { assert.throws(function () { unequal(bignumber(1).div(3), 1 / 3) }, /TypeError: Cannot implicitly convert a number with >15 significant digits to BigNumber/) }) + it('should compare mixed numbers and bigints', function () { + assert.deepStrictEqual(unequal(2n, 3), true) + assert.deepStrictEqual(unequal(2, 2n), false) + + assert.throws(function () { unequal(123123123123123123123n, 1) }, /Cannot implicitly convert bigint to number: value exceeds the max safe integer value/) + assert.throws(function () { unequal(1, 123123123123123123123n) }, /Cannot implicitly convert bigint to number: value exceeds the max safe integer value/) + }) + it('should compare mixed booleans and bignumbers', function () { assert.deepStrictEqual(unequal(bignumber(0.1), true), true) assert.deepStrictEqual(unequal(bignumber(1), true), false) diff --git a/test/unit-tests/function/statistics/max.test.js b/test/unit-tests/function/statistics/max.test.js index fcb6016bbb..2a6ccbcb55 100644 --- a/test/unit-tests/function/statistics/max.test.js +++ b/test/unit-tests/function/statistics/max.test.js @@ -24,6 +24,20 @@ describe('max', function () { assert.strictEqual(max('10'), 10) }) + it('should return the max of strings by their numerical value (with BigNumber config)', function () { + const bigmath = math.create({ number: 'BigNumber' }) + assert.deepStrictEqual(bigmath.max('10', '3', '4', '2'), bigmath.bignumber(10)) + assert.deepStrictEqual(bigmath.max('10'), bigmath.bignumber(10)) + }) + + it('should return the max of strings by their numerical value (with bigint config)', function () { + const bigmath = math.create({ number: 'bigint' }) + assert.strictEqual(bigmath.max('10', '3', '4', '2'), 10n) + assert.strictEqual(bigmath.max('10'), 10n) + assert.strictEqual(bigmath.max('2.5'), 2.5) // fallback to number + assert.strictEqual(bigmath.max('2.5', '4'), 4n) // fallback to number + }) + it('should return the max element from a vector', function () { assert.strictEqual(max(new DenseMatrix([1, 3, 5, 2, -5])), 5) }) diff --git a/test/unit-tests/function/statistics/min.test.js b/test/unit-tests/function/statistics/min.test.js index 8e690eda50..389ba2d26b 100644 --- a/test/unit-tests/function/statistics/min.test.js +++ b/test/unit-tests/function/statistics/min.test.js @@ -19,6 +19,20 @@ describe('min', function () { assert.strictEqual(min('10'), 10) }) + it('should return the max of strings by their numerical value (with BigNumber config)', function () { + const bigmath = math.create({ number: 'BigNumber' }) + assert.deepStrictEqual(bigmath.min('10', '3', '4', '2'), bigmath.bignumber(2)) + assert.deepStrictEqual(bigmath.min('10'), bigmath.bignumber(10)) + }) + + it('should return the max of strings by their numerical value (with bigint config)', function () { + const bigmath = math.create({ number: 'bigint' }) + assert.strictEqual(bigmath.min('10', '3', '4', '2'), 2n) + assert.strictEqual(bigmath.min('10'), 10n) + assert.strictEqual(bigmath.min('2.5'), 2.5) // fallback to number + assert.strictEqual(bigmath.min('2.5', '4'), 2.5) // fallback to number + }) + it('should return the min element from a vector', function () { assert.strictEqual(min([1, 3, 5, -5, 2]), -5) }) diff --git a/test/unit-tests/function/statistics/prod.test.js b/test/unit-tests/function/statistics/prod.test.js index d280724188..87d43d5aa7 100644 --- a/test/unit-tests/function/statistics/prod.test.js +++ b/test/unit-tests/function/statistics/prod.test.js @@ -25,6 +25,24 @@ describe('prod', function () { assert.strictEqual(prod([['1', '3'], ['5', '2']]), 30) }) + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should return the product of strings (with BigNumber config)', function () { + // TODO: requires math.add to recon with config.number when parsing strings + const bigmath = math.create({ number: 'BigNumber' }) + assert.deepStrictEqual(bigmath.prod('10', '3', '4', '2'), bigmath.bignumber('240')) + assert.deepStrictEqual(bigmath.prod('10'), bigmath.bignumber(10)) + }) + + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should return the product of strings (with bigint config)', function () { + // TODO: requires math.add to recon with config.number when parsing strings + const bigmath = math.create({ number: 'bigint' }) + assert.strictEqual(bigmath.prod('10', '3', '4', '2'), 240n) + assert.strictEqual(bigmath.prod('10'), 10n) + assert.strictEqual(bigmath.prod('2.5'), 2.5) // fallback to number + assert.strictEqual(bigmath.prod('2.5', '4'), 10) // fallback to number + }) + it('should return the product of complex numbers', function () { assert.deepStrictEqual(prod(new Complex(2, 3), new Complex(-1, 2)), new Complex(-8, 1)) }) diff --git a/test/unit-tests/function/statistics/sum.test.js b/test/unit-tests/function/statistics/sum.test.js index 6c785c65c1..f802d4829b 100644 --- a/test/unit-tests/function/statistics/sum.test.js +++ b/test/unit-tests/function/statistics/sum.test.js @@ -27,6 +27,24 @@ describe('sum', function () { assert.strictEqual(sum([['2', '3'], ['4', '5']]), 14) }) + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should return the max of strings by their numerical value (with BigNumber config)', function () { + // TODO: requires math.add to recon with config.number when parsing strings + const bigmath = math.create({ number: 'BigNumber' }) + assert.deepStrictEqual(bigmath.sum('10', '3', '4', '2'), bigmath.bignumber('19')) + assert.deepStrictEqual(bigmath.sum('10'), bigmath.bignumber(10)) + }) + + // eslint-disable-next-line mocha/no-skipped-tests + it.skip('should return the max of strings by their numerical value (with bigint config)', function () { + // TODO: requires math.add to recon with config.number when parsing strings + const bigmath = math.create({ number: 'bigint' }) + assert.strictEqual(bigmath.sum('10', '3', '4', '2'), 19n) + assert.strictEqual(bigmath.sum('10'), 10n) + assert.strictEqual(bigmath.sum('2.5'), 2.5) // fallback to number + assert.strictEqual(bigmath.sum('2.5', '4'), 6.5) // fallback to number + }) + it('should return the sum of complex numbers', function () { assert.deepStrictEqual(sum(new Complex(2, 3), new Complex(-1, 2)), new Complex(1, 5)) }) diff --git a/test/unit-tests/function/string/format.test.js b/test/unit-tests/function/string/format.test.js index 04c851c7e1..8469a571d6 100644 --- a/test/unit-tests/function/string/format.test.js +++ b/test/unit-tests/function/string/format.test.js @@ -12,6 +12,12 @@ describe('format', function () { assert.strictEqual(math.format(2.3e6), '2.3e+6') }) + it('should format bigints', function () { + assert.strictEqual(math.format(42n), '42') + assert.strictEqual(math.format(-4n), '-4') + assert.strictEqual(math.format(123123123123123123123n), '123123123123123123123') + }) + it('should format strings', function () { assert.strictEqual(math.format('hello'), '"hello"') }) diff --git a/test/unit-tests/function/string/print.test.js b/test/unit-tests/function/string/print.test.js index cfeadcf27e..9ce4a7ca2d 100644 --- a/test/unit-tests/function/string/print.test.js +++ b/test/unit-tests/function/string/print.test.js @@ -8,6 +8,10 @@ describe('print', function () { assert.strictEqual(math.print('hello, $name!', { name: 'user' }), 'hello, user!') }) + it('should print a bigint', function () { + assert.strictEqual(math.print('The count is: $count', { count: 3n }), 'The count is: 3') + }) + it('should interpolate values from a nested object in a template (object template)', function () { assert.strictEqual(math.print('hello, $name.first $name.last!', { name: { diff --git a/test/unit-tests/function/utils/clone.test.js b/test/unit-tests/function/utils/clone.test.js index 39d0f5d9e0..6b82d1ec54 100644 --- a/test/unit-tests/function/utils/clone.test.js +++ b/test/unit-tests/function/utils/clone.test.js @@ -19,6 +19,14 @@ describe('clone', function () { assert.strictEqual(b, 1) }) + it('should clone a bigint', function () { + let a = 1n + const b = math.clone(a) + a = 2n + assert.strictEqual(a, 2n) + assert.strictEqual(b, 1n) + }) + it('should throw an error on wrong number of arguments', function () { assert.throws(function () { math.clone() }, /TypeError: Too few arguments/) assert.throws(function () { math.clone(2, 4) }, /TypeError: Too many arguments/) diff --git a/test/unit-tests/function/utils/hasNumericValue.test.js b/test/unit-tests/function/utils/hasNumericValue.test.js index f9ebdf3ffc..8f0b5d4312 100644 --- a/test/unit-tests/function/utils/hasNumericValue.test.js +++ b/test/unit-tests/function/utils/hasNumericValue.test.js @@ -3,6 +3,7 @@ import math from '../../../../src/defaultInstance.js' const hasNumericValue = math.hasNumericValue const bignumber = math.bignumber +const bigint = math.bigint const fraction = math.fraction describe('hasNumericValue', function () { @@ -10,6 +11,8 @@ describe('hasNumericValue', function () { assert.strictEqual(hasNumericValue(2), true) assert.strictEqual(hasNumericValue(true), true) assert.strictEqual(hasNumericValue(bignumber(2.3)), true) + assert.strictEqual(hasNumericValue(bigint('42')), true) + assert.strictEqual(hasNumericValue(42n), true) assert.strictEqual(hasNumericValue(fraction(1, 3)), true) assert.strictEqual(hasNumericValue('2'), true) diff --git a/test/unit-tests/function/utils/isInteger.test.js b/test/unit-tests/function/utils/isInteger.test.js index c1008e88fd..6edba354de 100644 --- a/test/unit-tests/function/utils/isInteger.test.js +++ b/test/unit-tests/function/utils/isInteger.test.js @@ -17,6 +17,12 @@ describe('isInteger', function () { assert.strictEqual(isInteger(0.1 + 0.2), false) // TODO: what to do with round off errors? }) + it('should test whether a bigint is an integer', function () { + assert.strictEqual(isInteger(2n), true) + assert.strictEqual(isInteger(0n), true) + assert.strictEqual(isInteger(-3n), true) + }) + it('should test whether a boolean is an integer', function () { assert.strictEqual(isInteger(true), true) assert.strictEqual(isInteger(false), true) diff --git a/test/unit-tests/function/utils/isNaN.test.js b/test/unit-tests/function/utils/isNaN.test.js index e7e586da05..95dc67c0ed 100644 --- a/test/unit-tests/function/utils/isNaN.test.js +++ b/test/unit-tests/function/utils/isNaN.test.js @@ -16,6 +16,12 @@ describe('isNegative', function () { assert.strictEqual(isNaN(NaN), true) }) + it('should test whether a bigint is NaN', function () { + assert.strictEqual(isNaN(0n), false) + assert.strictEqual(isNaN(2n), false) + assert.strictEqual(isNaN(-3n), false) + }) + it('should test whether a boolean is NaN', function () { assert.strictEqual(isNaN(true), false) assert.strictEqual(isNaN(false), false) diff --git a/test/unit-tests/function/utils/isNegative.test.js b/test/unit-tests/function/utils/isNegative.test.js index 2b0a5cd8f9..7477221285 100644 --- a/test/unit-tests/function/utils/isNegative.test.js +++ b/test/unit-tests/function/utils/isNegative.test.js @@ -17,6 +17,13 @@ describe('isNegative', function () { assert.strictEqual(isNegative(NaN), false) }) + it('should test whether a bigint is negative', function () { + assert.strictEqual(isNegative(0n), false) + assert.strictEqual(isNegative(-0n), false) + assert.strictEqual(isNegative(2n), false) + assert.strictEqual(isNegative(-3n), true) + }) + it('should test whether a number is near negative', function () { assert.strictEqual(isNegative(1e-17), false) assert.strictEqual(isNegative(-1e-17), false) diff --git a/test/unit-tests/function/utils/isNumeric.test.js b/test/unit-tests/function/utils/isNumeric.test.js index fc7f3757f6..829c216de9 100644 --- a/test/unit-tests/function/utils/isNumeric.test.js +++ b/test/unit-tests/function/utils/isNumeric.test.js @@ -2,6 +2,7 @@ import assert from 'assert' import math from '../../../../src/defaultInstance.js' const isNumeric = math.isNumeric const bignumber = math.bignumber +const bigint = math.bigint const fraction = math.fraction describe('isNumeric', function () { @@ -9,6 +10,8 @@ describe('isNumeric', function () { assert.strictEqual(isNumeric(2), true) assert.strictEqual(isNumeric(true), true) assert.strictEqual(isNumeric(bignumber(2.3)), true) + assert.strictEqual(isNumeric(bigint('42')), true) + assert.strictEqual(isNumeric(42n), true) assert.strictEqual(isNumeric(fraction(1, 3)), true) assert.strictEqual(isNumeric('2'), false) diff --git a/test/unit-tests/function/utils/isPositive.test.js b/test/unit-tests/function/utils/isPositive.test.js index ac513d9d5a..c9be9f3d6d 100644 --- a/test/unit-tests/function/utils/isPositive.test.js +++ b/test/unit-tests/function/utils/isPositive.test.js @@ -17,6 +17,13 @@ describe('isPositive', function () { assert.strictEqual(isPositive(NaN), false) }) + it('should test whether a bigint is positive', function () { + assert.strictEqual(isPositive(0n), false) + assert.strictEqual(isPositive(-0n), false) + assert.strictEqual(isPositive(2n), true) + assert.strictEqual(isPositive(-3n), false) + }) + it('should test whether a number is near positive', function () { assert.strictEqual(isPositive(1e-17), false) assert.strictEqual(isPositive(-1e-17), false) diff --git a/test/unit-tests/function/utils/isPrime.test.js b/test/unit-tests/function/utils/isPrime.test.js index 02d60e8417..0c865645a6 100644 --- a/test/unit-tests/function/utils/isPrime.test.js +++ b/test/unit-tests/function/utils/isPrime.test.js @@ -20,6 +20,21 @@ describe('isPrime', function () { assert.strictEqual(isPrime(999), false) }) + it('should test whether a bigint is prime', function () { + assert.strictEqual(isPrime(0n), false) + assert.strictEqual(isPrime(-0n), false) + assert.strictEqual(isPrime(-1n), false) + assert.strictEqual(isPrime(1n), false) + assert.strictEqual(isPrime(2n), true) + assert.strictEqual(isPrime(3n), true) + assert.strictEqual(isPrime(5n), true) + assert.strictEqual(isPrime(7n), true) + assert.strictEqual(isPrime(4n), false) + assert.strictEqual(isPrime(100n), false) + assert.strictEqual(isPrime(102n), false) + assert.strictEqual(isPrime(999n), false) + }) + it('should test whether a BigNumber is prime', function () { assert.strictEqual(isPrime(bignumber(0)), false) assert.strictEqual(isPrime(bignumber(-0)), false) diff --git a/test/unit-tests/function/utils/isZero.test.js b/test/unit-tests/function/utils/isZero.test.js index 12c2216904..297613169a 100644 --- a/test/unit-tests/function/utils/isZero.test.js +++ b/test/unit-tests/function/utils/isZero.test.js @@ -19,6 +19,13 @@ describe('isZero', function () { assert.strictEqual(isZero(NaN), false) }) + it('should test whether a bigint is zero', function () { + assert.strictEqual(isZero(0n), true) + assert.strictEqual(isZero(-0n), true) + assert.strictEqual(isZero(2n), false) + assert.strictEqual(isZero(-3n), false) + }) + it('should test whether a number is near zero', function () { assert.strictEqual(isZero(1e-17), true) assert.strictEqual(isZero(1e-16), true) diff --git a/test/unit-tests/function/utils/typeof.test.js b/test/unit-tests/function/utils/typeof.test.js index eee698e1c9..a5ca7473dd 100644 --- a/test/unit-tests/function/utils/typeof.test.js +++ b/test/unit-tests/function/utils/typeof.test.js @@ -18,6 +18,11 @@ describe('typeOf', function () { assert.strictEqual(math.typeOf(NaN), 'number') }) + it('should return bignumber type for a bigint', function () { + assert.strictEqual(math.typeOf(42n), 'bigint') + assert.strictEqual(math.typeOf(math.bigint('42')), 'bigint') + }) + it('should return bignumber type for a bignumber', function () { assert.strictEqual(math.typeOf(math.bignumber(0.1)), 'BigNumber') assert.strictEqual(math.typeOf(new math.BigNumber('0.2')), 'BigNumber') diff --git a/test/unit-tests/json/replacer.test.js b/test/unit-tests/json/replacer.test.js index d5dcc7c758..c03c46be74 100644 --- a/test/unit-tests/json/replacer.test.js +++ b/test/unit-tests/json/replacer.test.js @@ -33,6 +33,13 @@ describe('replacer', function () { assert.deepStrictEqual(JSON.stringify(b, replacer), json) }) + it('should stringify a bigint', function () { + const b = 12345678901234567890n + const json = '{"mathjs":"bigint","value":"12345678901234567890"}' + + assert.deepStrictEqual(JSON.stringify(b, replacer), json) + }) + it('should stringify a Fraction', function () { const b = new math.Fraction(0.375) const json = '{"mathjs":"Fraction","n":3,"d":8}' diff --git a/test/unit-tests/json/reviver.test.js b/test/unit-tests/json/reviver.test.js index 7c7ca24059..ae0fc3505c 100644 --- a/test/unit-tests/json/reviver.test.js +++ b/test/unit-tests/json/reviver.test.js @@ -38,6 +38,12 @@ describe('reviver', function () { assert.deepStrictEqual(obj, b) }) + it('should parse a stringified bigint', function () { + const json = '{"mathjs":"bigint","value":"12345678901234567890"}' + + assert.deepStrictEqual(JSON.parse(json, reviver), 12345678901234567890n) + }) + it('should parse a stringified Fraction', function () { const json = '{"mathjs":"Fraction","n":3,"d":8}' const b = new math.Fraction(0.375) diff --git a/test/unit-tests/type/bigint.test.js b/test/unit-tests/type/bigint.test.js new file mode 100644 index 0000000000..3a5d536f77 --- /dev/null +++ b/test/unit-tests/type/bigint.test.js @@ -0,0 +1,81 @@ +import assert from 'assert' +import math from '../../../src/defaultInstance.js' + +const bigint = math.bigint + +describe('bigint', function () { + it('should be 0 if called with no argument', function () { + assert.strictEqual(bigint(), 0n) + }) + + it('should convert a boolean to a bigint', function () { + assert.strictEqual(bigint(true), 1n) + assert.strictEqual(bigint(false), 0n) + }) + + it('should convert null to a bigint', function () { + assert.strictEqual(bigint(null), 0n) + }) + + it('should convert a BigNumber to a bigint', function () { + assert.strictEqual(bigint(math.bignumber('123')), 123n) + assert.strictEqual(bigint(math.bignumber('2.3')), 2n) + }) + + it('should convert a number to a bigint', function () { + assert.strictEqual(bigint(123), 123n) + assert.strictEqual(bigint(2.3), 2n) + }) + + it('should convert a Fraction to a bigint', function () { + assert.strictEqual(bigint(math.fraction(7, 3)), 2n) + }) + + it('should accept a bigint as argument', function () { + assert.strictEqual(bigint(3n), 3n) + assert.strictEqual(bigint(-3n), -3n) + }) + + it('should parse the string if called with a valid string', function () { + assert.strictEqual(bigint('2100'), 2100n) + assert.strictEqual(bigint(' -2100 '), -2100n) + assert.strictEqual(bigint(''), 0n) + assert.strictEqual(bigint(' '), 0n) + }) + + it('should throw an error if called with an invalid string', function () { + assert.throws(function () { bigint('2.3') }, SyntaxError) + assert.throws(function () { bigint('2.3.4') }, SyntaxError) + assert.throws(function () { bigint('23a') }, SyntaxError) + }) + + it('should convert the elements of a matrix to numbers', function () { + assert.deepStrictEqual(bigint(math.matrix(['123', true])), math.matrix([123n, 1n])) + }) + + it('should convert the elements of an array to numbers', function () { + assert.deepStrictEqual(bigint(['123', true]), [123n, 1n]) + }) + + it('should throw an error if called with a wrong number of arguments', function () { + assert.throws(function () { bigint(1, 2, 3) }, /TypeError: Too many arguments/) + }) + + it('should throw an error if called with a complex number', function () { + assert.throws(function () { bigint(math.complex(2, 3)) }, TypeError) + }) + + it('should throw an error with wrong type of arguments', function () { + assert.throws(function () { bigint(math.unit('5cm'), 2) }, TypeError) + assert.throws(function () { bigint(math.unit('5cm'), new Date()) }, TypeError) + assert.throws(function () { bigint('23', 2) }, TypeError) + }) + + it('should LaTeX bigint', function () { + const expr1 = math.parse('bigint()') + const expr2 = math.parse('bigint(1)') + + assert.strictEqual(expr1.toTex(), '0') + assert.strictEqual(expr2.toTex(), '\\left(1\\right)') + }) +}) diff --git a/test/unit-tests/type/bignumber/function/bignumber.test.js b/test/unit-tests/type/bignumber/function/bignumber.test.js index 5e07d69b11..3e02143c57 100644 --- a/test/unit-tests/type/bignumber/function/bignumber.test.js +++ b/test/unit-tests/type/bignumber/function/bignumber.test.js @@ -71,6 +71,10 @@ describe('bignumber', function () { assert.strictEqual(b.toString(), '0.6666666666666666666666666666666666666666666666666666666666666667') }) + it('should create a bignumber from a bigint', function () { + assert.deepStrictEqual(math.bignumber(12345678901234567890n), new BigNumber('12345678901234567890')) + }) + it('should convert the number value of a Unit to BigNumber', function () { const b = math.bignumber(math.unit(10, 'inch')).toNumeric('cm') diff --git a/test/unit-tests/type/fraction/function/fraction.test.js b/test/unit-tests/type/fraction/function/fraction.test.js index 00cd5d9c5e..edf852654b 100644 --- a/test/unit-tests/type/fraction/function/fraction.test.js +++ b/test/unit-tests/type/fraction/function/fraction.test.js @@ -32,6 +32,10 @@ describe('fraction', function () { equalFraction(f, new Fraction('0.6666666666666666666666666666666666666666666666666666666666666667')) }) + it('should create a fraction from a bigint', function () { + equalFraction(math.fraction(42n), new Fraction('42')) + }) + it('should convert the number value of a Unit to Fraction', function () { equalFraction(math.fraction(math.unit(0.5, 'cm')).toNumeric('cm'), new Fraction(1, 2)) equalFraction(math.fraction(math.unit(10, 'inch')).toNumeric('cm'), new Fraction(127, 5)) diff --git a/test/unit-tests/type/number.test.js b/test/unit-tests/type/number.test.js index dd4bf21a90..bf4f10a63c 100644 --- a/test/unit-tests/type/number.test.js +++ b/test/unit-tests/type/number.test.js @@ -1,5 +1,6 @@ import assert from 'assert' import math from '../../../src/defaultInstance.js' +import { isIntegerStr } from '../../../src/utils/number.js' import { approxEqual } from '../../../tools/approx.js' const number = math.number @@ -17,12 +18,17 @@ describe('number', function () { approxEqual(number(null), 0) }) - it('should convert a bignumber to a number', function () { + it('should convert a BigNumber to a number', function () { approxEqual(number(math.bignumber(0.1)), 0.1) approxEqual(number(math.bignumber('1.3e500')), Infinity) }) - it('should convert a fraction to a number', function () { + it('should convert a bigint to a number', function () { + assert.strictEqual(number(123n), 123) + assert.strictEqual(number(12345678901234567890n).toString(), '12345678901234567000') // note: we've lost digits here + }) + + it('should convert a Fraction to a number', function () { approxEqual(number(math.fraction(2, 5)), 0.4) }) @@ -35,6 +41,17 @@ describe('number', function () { approxEqual(number(math.unit('52cm'), 'm'), 0.52) }) + it('should test whether a string contains an integer', function () { + assert.strictEqual(isIntegerStr('123'), true) + assert.strictEqual(isIntegerStr('-123'), true) + assert.strictEqual(isIntegerStr('123123123123123123123123123123123'), true) + assert.strictEqual(isIntegerStr('-123123123123123123123123123123123'), true) + assert.strictEqual(isIntegerStr('2.4'), false) + assert.strictEqual(isIntegerStr('2e3'), false) + assert.strictEqual(isIntegerStr(''), false) + assert.strictEqual(isIntegerStr('a'), false) + }) + it('should convert the value of a unit to a number', function () { const value = number(math.unit(math.bignumber(52), 'cm')) assert.strictEqual(value.toNumeric('cm'), 52) diff --git a/test/unit-tests/utils/is.test.js b/test/unit-tests/utils/is.test.js index f5080aaf57..c5c008fc67 100644 --- a/test/unit-tests/utils/is.test.js +++ b/test/unit-tests/utils/is.test.js @@ -1,6 +1,7 @@ import assert from 'assert' -import { isBoolean, isNumber, isObject, isString } from '../../../src/utils/is.js' import math from '../../../src/defaultInstance.js' +import { isBigInt, isBoolean, isNumber, isObject, isString } from '../../../src/utils/is.js' + const { bignumber, complex, fraction, matrix, parse } = math describe('is', function () { @@ -60,4 +61,12 @@ describe('is', function () { assert.strictEqual(isNumber(undefined), false) assert.strictEqual(isNumber(), false) }) + + it('isBigInt', function () { + assert.strictEqual(isBigInt(2n), true) + assert.strictEqual(isBigInt(BigInt(2)), true) + assert.strictEqual(isBigInt(2), false) + assert.strictEqual(isBigInt(), false) + assert.strictEqual(isBigInt(null), false) + }) }) diff --git a/test/unit-tests/utils/object.test.js b/test/unit-tests/utils/object.test.js index 098ff63027..103200ce6d 100644 --- a/test/unit-tests/utils/object.test.js +++ b/test/unit-tests/utils/object.test.js @@ -33,6 +33,10 @@ describe('object', function () { assert.strictEqual(clone(2.3), 2.3) }) + it('should clone bigint', function () { + assert.strictEqual(clone(4n), 4n) + }) + it('should clone strings', function () { assert.strictEqual(clone('hello'), 'hello') }) diff --git a/tsconfig.json b/tsconfig.json index 65e05c024d..669c88c5a6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,7 +8,11 @@ "moduleResolution": "nodenext", "typeRoots": [], "types": [], - "lib": ["ES6", "DOM"], + "lib": [ + "ES6", + "DOM", + "es2020.bigint" + ], "module": "NodeNext", "noEmit": true, "noImplicitAny": true, diff --git a/types/index.d.ts b/types/index.d.ts index 046ac18d32..f73a6be38a 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -11,7 +11,7 @@ export type NoLiteralType = T extends number : T // TODO: introduce generics for MathCollection, MathMatrix, and MathArray -export type MathNumericType = number | BigNumber | Fraction | Complex +export type MathNumericType = number | BigNumber | bigint | Fraction | Complex export type MathScalarType = MathNumericType | Unit export type MathArray = MathNumericType[] | MathNumericType[][] // TODO: MathArray can also contain Unit export type MathCollection = MathArray | Matrix @@ -587,10 +587,22 @@ export interface MathJsInstance extends MathJsFactory { * @returns The created bignumber */ bignumber( - x?: number | string | Fraction | BigNumber | Unit | boolean | null + x?: number | string | Fraction | BigNumber | bigint | Unit | boolean | null ): BigNumber bignumber(x: T): T + /** + * Create a bigint, which can store integers with arbitrary precision. + * When a matrix is provided, all elements will be converted to + * bigint. + * @param x Value for the integer, 0 by default. + * @returns The created bigint + */ + bigint( + x?: number | string | Fraction | BigNumber | bigint | boolean | null + ): bigint + bigint(x: T): T + /** * Create a boolean or convert a string or number to a boolean. In case * of a number, true is returned for non-zero numbers, and false in case @@ -671,7 +683,14 @@ export interface MathJsInstance extends MathJsFactory { * @returns Returns a fraction */ fraction( - value: number | string | BigNumber | Unit | Fraction | FractionDefinition + value: + | number + | string + | BigNumber + | bigint + | Unit + | Fraction + | FractionDefinition ): Fraction fraction(values: MathCollection): MathCollection /** @@ -720,7 +739,15 @@ export interface MathJsInstance extends MathJsFactory { * @returns The created number */ number( - value?: string | number | BigNumber | Fraction | boolean | Unit | null + value?: + | string + | number + | BigNumber + | bigint + | Fraction + | boolean + | Unit + | null ): number number(value?: MathCollection): number | MathCollection /** @@ -731,6 +758,28 @@ export interface MathJsInstance extends MathJsFactory { */ number(unit: Unit, valuelessUnit: Unit | string): number + /** + * Convert a numeric input to a specific numeric type: number, BigNumber, bigint, or Fraction. + * @param value The value to be converted + * @param outputType The desired numeric output type + */ + numeric( + value: string | number | BigNumber | bigint | Fraction, + outputType: 'number' + ): number + numeric( + value: string | number | BigNumber | bigint | Fraction, + outputType: 'BigNumber' + ): BigNumber + numeric( + value: string | number | BigNumber | bigint | Fraction, + outputType: 'bigint' + ): bigint + numeric( + value: string | number | BigNumber | bigint | Fraction, + outputType: 'Fraction' + ): Fraction + /** * Create a Sparse Matrix. The function creates a new math.type.Matrix * object from an Array. A Matrix has utility functions to manipulate @@ -1265,9 +1314,9 @@ export interface MathJsInstance extends MathJsFactory { * @param y Divisor * @returns Returns the remainder of x divided by y */ - mod( + mod( x: T, - y: number | BigNumber | Fraction | MathCollection + y: number | BigNumber | bigint | Fraction | MathCollection ): NoLiteralType /** @@ -1324,7 +1373,7 @@ export interface MathJsInstance extends MathJsFactory { * @param y The exponent * @returns x to the power y */ - pow(x: MathType, y: number | BigNumber | Complex): MathType + pow(x: MathType, y: number | BigNumber | bigint | Complex): MathType /** * Compute the sign of a value. The sign of a value x is: 1 when x > 1 @@ -1403,9 +1452,9 @@ export interface MathJsInstance extends MathJsFactory { * @param y Second value to and * @returns AND of x and y */ - bitAnd( + bitAnd( x: T, - y: number | BigNumber | MathCollection + y: number | BigNumber | bigint | MathCollection ): NoLiteralType /** @@ -1415,7 +1464,7 @@ export interface MathJsInstance extends MathJsFactory { * @param x Value to not * @returns NOT of x */ - bitNot(x: T): T + bitNot(x: T): T /** * Bitwise OR two values, x | y. For matrices, the function is evaluated @@ -1425,7 +1474,7 @@ export interface MathJsInstance extends MathJsFactory { * @param y Second value to or * @returns OR of x and y */ - bitOr(x: T, y: T): T + bitOr(x: T, y: T): T /** * Bitwise XOR two values, x ^ y. For matrices, the function is @@ -1434,9 +1483,9 @@ export interface MathJsInstance extends MathJsFactory { * @param y Second value to xor * @returns XOR of x and y */ - bitXor( + bitXor( x: T, - y: number | BigNumber | MathCollection + y: number | BigNumber | bigint | MathCollection ): NoLiteralType /** @@ -1447,9 +1496,9 @@ export interface MathJsInstance extends MathJsFactory { * @param y Amount of shifts * @returns x shifted left y times */ - leftShift( + leftShift( x: T, - y: number | BigNumber + y: number | BigNumber | bigint ): NoLiteralType /** @@ -1460,9 +1509,9 @@ export interface MathJsInstance extends MathJsFactory { * @param y Amount of shifts * @returns x sign-filled shifted right y times */ - rightArithShift( + rightArithShift( x: T, - y: number | BigNumber + y: number | BigNumber | bigint ): NoLiteralType /** @@ -1633,8 +1682,8 @@ export interface MathJsInstance extends MathJsFactory { * nonzero/nonempty value. */ and( - x: number | BigNumber | Complex | Unit | MathCollection, - y: number | BigNumber | Complex | Unit | MathCollection + x: number | BigNumber | bigint | Complex | Unit | MathCollection, + y: number | BigNumber | bigint | Complex | Unit | MathCollection ): boolean | MathCollection /** @@ -1644,7 +1693,7 @@ export interface MathJsInstance extends MathJsFactory { * @returns Returns true when input is a zero or empty value. */ not( - x: number | BigNumber | Complex | Unit | MathCollection + x: number | BigNumber | bigint | Complex | Unit | MathCollection ): boolean | MathCollection /** @@ -1657,8 +1706,8 @@ export interface MathJsInstance extends MathJsFactory { * nonzero/nonempty value. */ or( - x: number | BigNumber | Complex | Unit | MathCollection, - y: number | BigNumber | Complex | Unit | MathCollection + x: number | BigNumber | bigint | Complex | Unit | MathCollection, + y: number | BigNumber | bigint | Complex | Unit | MathCollection ): boolean | MathCollection /** @@ -1671,8 +1720,8 @@ export interface MathJsInstance extends MathJsFactory { * nonzero/nonempty value. */ xor( - x: number | BigNumber | Complex | Unit | MathCollection, - y: number | BigNumber | Complex | Unit | MathCollection + x: number | BigNumber | bigint | Complex | Unit | MathCollection, + y: number | BigNumber | bigint | Complex | Unit | MathCollection ): boolean | MathCollection /************************************************************************* @@ -3292,6 +3341,8 @@ export interface MathJsInstance extends MathJsFactory { isBigNumber(x: unknown): x is BigNumber + isBigInt(x: unknown): x is bigint + isComplex(x: unknown): x is Complex isFraction(x: unknown): x is Fraction @@ -3383,7 +3434,7 @@ export interface MathJsInstance extends MathJsFactory { * Test whether a value is an numeric value. In case of a string, * true is returned if the string contains a numeric value. * @param x Value to be tested - * @returns Returns true when x is a number, BigNumber, Fraction, Boolean, or a String containing number. + * @returns Returns true when x is a number, BigNumber, bigint, Fraction, Boolean, or a String containing number. * Returns false for other types. * Throws an error in case of unknown types. */ @@ -3408,7 +3459,9 @@ export interface MathJsInstance extends MathJsFactory { * @returns Returns true when x is NaN. Throws an error in case of an * unknown data type. */ - isNaN(x: number | BigNumber | Fraction | MathCollection | Unit): boolean + isNaN( + x: number | BigNumber | bigint | Fraction | MathCollection | Unit + ): boolean /** * Test whether a value is negative: smaller than zero. The function @@ -3418,18 +3471,20 @@ export interface MathJsInstance extends MathJsFactory { * @returns Returns true when x is larger than zero. Throws an error in * case of an unknown data type. */ - isNegative(x: number | BigNumber | Fraction | MathCollection | Unit): boolean + isNegative( + x: number | BigNumber | bigint | Fraction | MathCollection | Unit + ): boolean /** * Test whether a value is an numeric value. The function is evaluated * element-wise in case of Array or Matrix input. * @param x Value to be tested - * @returns Returns true when x is a number, BigNumber, Fraction, or + * @returns Returns true when x is a number, BigNumber, bigint, Fraction, or * boolean. Returns false for other types. Throws an error in case of * unknown types. */ // eslint-disable-next-line @typescript-eslint/no-explicit-any - isNumeric(x: any): x is number | BigNumber | Fraction | boolean + isNumeric(x: any): x is number | BigNumber | bigint | Fraction | boolean /** * Test whether a value is positive: larger than zero. The function @@ -3439,7 +3494,9 @@ export interface MathJsInstance extends MathJsFactory { * @returns Returns true when x is larger than zero. Throws an error in * case of an unknown data type. */ - isPositive(x: number | BigNumber | Fraction | MathCollection | Unit): boolean + isPositive( + x: number | BigNumber | bigint | Fraction | MathCollection | Unit + ): boolean /** * Test whether a value is prime: has no divisors other than itself and @@ -4318,7 +4375,8 @@ export interface ConfigOptions { */ epsilon?: number matrix?: 'Matrix' | 'Array' - number?: 'number' | 'BigNumber' | 'Fraction' + number?: 'number' | 'BigNumber' | 'bigint' | 'Fraction' + numberFallback?: 'number' | 'BigNumber' precision?: number predictable?: boolean randomSeed?: string | null @@ -4339,11 +4397,22 @@ export interface MathJsChain { */ bignumber( this: MathJsChain< - number | string | Fraction | BigNumber | Unit | boolean | null + number | string | Fraction | BigNumber | bigint | Unit | boolean | null > ): MathJsChain bignumber(this: MathJsChain): MathJsChain + /** + * Create a bigint, which can store integers with arbitrary precision. + * When a matrix is provided, all elements will be converted to bigint. + */ + bigint( + this: MathJsChain< + number | string | Fraction | BigNumber | bigint | boolean | null + > + ): MathJsChain + bigint(this: MathJsChain): MathJsChain + /** * Create a boolean or convert a string or number to a boolean. In case * of a number, true is returned for non-zero numbers, and false in case @@ -4405,7 +4474,13 @@ export interface MathJsChain { */ fraction( this: MathJsChain< - number | string | BigNumber | Unit | Fraction | FractionDefinition + | number + | string + | BigNumber + | bigint + | Unit + | Fraction + | FractionDefinition >, denominator?: number ): MathJsChain @@ -4439,7 +4514,7 @@ export interface MathJsChain { */ number( this: MathJsChain< - string | number | BigNumber | Fraction | boolean | Unit | null + string | number | BigNumber | bigint | Fraction | boolean | Unit | null >, valuelessUnit?: Unit | string ): MathJsChain @@ -4448,6 +4523,27 @@ export interface MathJsChain { valuelessUnit?: Unit | string ): MathJsChain + /** + * Convert a numeric input to a specific numeric type: number, BigNumber, bigint, or Fraction. + * @param outputType The desired numeric output type + */ + numeric( + this: MathJsChain, + outputType: 'number' + ): MathJsChain + numeric( + this: MathJsChain, + outputType: 'BigNumber' + ): MathJsChain + numeric( + this: MathJsChain, + outputType: 'bigint' + ): MathJsChain + numeric( + this: MathJsChain, + outputType: 'Fraction' + ): MathJsChain + /** * Create a Sparse Matrix. The function creates a new math.type.Matrix * object from an Array. A Matrix has utility functions to manipulate @@ -4969,9 +5065,9 @@ export interface MathJsChain { * @see http://en.wikipedia.org/wiki/Modulo_operation. * @param y Divisor */ - mod( + mod( this: MathJsChain, - y: number | BigNumber | Fraction | MathCollection + y: number | BigNumber | bigint | Fraction | MathCollection ): MathJsChain> /** @@ -5017,7 +5113,7 @@ export interface MathJsChain { */ pow( this: MathJsChain, - y: number | BigNumber | Complex + y: number | BigNumber | bigint | Complex ): MathJsChain /** @@ -5103,9 +5199,9 @@ export interface MathJsChain { * evaluated element wise. * @param y Second value to and */ - bitAnd( + bitAnd( this: MathJsChain, - y: number | BigNumber | MathCollection + y: number | BigNumber | bigint | MathCollection ): MathJsChain> /** @@ -5114,7 +5210,7 @@ export interface MathJsChain { * base. */ - bitNot( + bitNot( this: MathJsChain ): MathJsChain @@ -5124,7 +5220,7 @@ export interface MathJsChain { * print base. * @param y Second value to or */ - bitOr( + bitOr( this: MathJsChain, y: T ): MathJsChain @@ -5134,9 +5230,9 @@ export interface MathJsChain { * evaluated element wise. * @param y Second value to xor */ - bitXor( + bitXor( this: MathJsChain, - y: number | BigNumber | MathCollection + y: number | BigNumber | bigint | MathCollection ): MathJsChain> /** @@ -5145,9 +5241,9 @@ export interface MathJsChain { * function is evaluated on the best prefix base. * @param y Amount of shifts */ - leftShift( + leftShift( this: MathJsChain, - y: number | BigNumber + y: number | BigNumber | bigint ): MathJsChain> /** @@ -5156,9 +5252,9 @@ export interface MathJsChain { * the function is evaluated on the best prefix base. * @param y Amount of shifts */ - rightArithShift( + rightArithShift( this: MathJsChain, - y: number | BigNumber + y: number | BigNumber | bigint ): MathJsChain> /** @@ -5310,8 +5406,10 @@ export interface MathJsChain { * @param y Second value to and */ and( - this: MathJsChain, - y: number | BigNumber | Complex | Unit | MathCollection + this: MathJsChain< + number | BigNumber | bigint | Complex | Unit | MathCollection + >, + y: number | BigNumber | bigint | Complex | Unit | MathCollection ): MathJsChain /** @@ -5319,7 +5417,9 @@ export interface MathJsChain { * the function is evaluated element wise. */ not( - this: MathJsChain + this: MathJsChain< + number | BigNumber | bigint | Complex | Unit | MathCollection + > ): MathJsChain /** @@ -5329,8 +5429,10 @@ export interface MathJsChain { * @param y Second value to or */ or( - this: MathJsChain, - y: number | BigNumber | Complex | Unit | MathCollection + this: MathJsChain< + number | BigNumber | bigint | Complex | Unit | MathCollection + >, + y: number | BigNumber | bigint | Complex | Unit | MathCollection ): MathJsChain /** @@ -5340,8 +5442,10 @@ export interface MathJsChain { * @param y Second value to xor */ xor( - this: MathJsChain, - y: number | BigNumber | Complex | Unit | MathCollection + this: MathJsChain< + number | BigNumber | bigint | Complex | Unit | MathCollection + >, + y: number | BigNumber | bigint | Complex | Unit | MathCollection ): MathJsChain /************************************************************************* @@ -6591,7 +6695,7 @@ export interface MathJsChain { */ isInteger( - this: MathJsChain + this: MathJsChain ): MathJsChain /** @@ -6615,7 +6719,7 @@ export interface MathJsChain { ): MathJsChain /** - * Test whether a value is an numeric value. The function is evaluated + * Test whether a value is a numeric value. The function is evaluated * element-wise in case of Array or Matrix input. */ @@ -6629,7 +6733,9 @@ export interface MathJsChain { */ isPositive( - this: MathJsChain + this: MathJsChain< + number | BigNumber | bigint | Fraction | MathCollection | Unit + > ): MathJsChain /** @@ -6639,7 +6745,7 @@ export interface MathJsChain { */ isPrime( - this: MathJsChain + this: MathJsChain ): MathJsChain /**