Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ A common case is to implement a new function. This involves the following steps:
- Write documentation on the function in the source code comment of `myNewFunction.js`. This documentation is used to auto generate documentation on the website.
- Write embedded documentation for the new function in `./src/expression/embeddedDocs/function/arithmetic/myNewFunction.js`. Add the new documentation to the index file `./src/expression/embeddedDocs/embeddedDocs.js`.
- Write unit tests for the function in `./test/unit-tests/function/arithmetic/myNewFunction.test.js`.
- Write the necessary TypeScript definitions for the new function in `./types/index.d.ts`, and write tests for it in `./test/typescript-tests/testTypes.ts`. This is described in [./types/EXPLANATION.md](./types/EXPLANATION.md).
- Write the necessary TypeScript definitions for the new function in `./types/index.d.ts`, and write tests for it in `./test/typescript-tests/testTypes.ts`. This is described in [./types/EXPLANATION.md](./types/EXPLANATION.md) -- make sure to read that page, as Typescript definitions must be added in _multiple_ places in the code.
- Ensure the code style is ok by running `npm run lint` (run `npm run format` to fix the code style automatically).


Expand Down
4 changes: 4 additions & 0 deletions src/expression/embeddedDocs/embeddedDocs.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,8 @@ import { hasNumericValueDocs } from './function/utils/hasNumericValue.js'
import { hexDocs } from './function/utils/hex.js'
import { isIntegerDocs } from './function/utils/isInteger.js'
import { isNaNDocs } from './function/utils/isNaN.js'
import { isBoundedDocs } from './function/utils/isBounded.js'
import { isFiniteDocs } from './function/utils/isFinite.js'
import { isNegativeDocs } from './function/utils/isNegative.js'
import { isNumericDocs } from './function/utils/isNumeric.js'
import { isPositiveDocs } from './function/utils/isPositive.js'
Expand Down Expand Up @@ -598,6 +600,8 @@ export const embeddedDocs = {
oct: octDocs,
hex: hexDocs,
isNaN: isNaNDocs,
isBounded: isBoundedDocs,
isFinite: isFiniteDocs,
isInteger: isIntegerDocs,
isNegative: isNegativeDocs,
isNumeric: isNumericDocs,
Expand Down
14 changes: 14 additions & 0 deletions src/expression/embeddedDocs/function/utils/isBounded.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export const isBoundedDocs = {
name: 'isBounded',
category: 'Utils',
syntax: [
'isBounded(x)'
],
description: 'Test whether a value or its entries are bounded.',
examples: [
'isBounded(Infinity)',
'isBounded(bigint(3))',
'isBounded([3, -Infinity, -3])'
],
seealso: ['isFinite', 'isNumeric', 'isNaN', 'isNegative', 'isPositive']
}
14 changes: 14 additions & 0 deletions src/expression/embeddedDocs/function/utils/isFinite.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export const isFiniteDocs = {
name: 'isFinite',
category: 'Utils',
syntax: [
'isFinite(x)'
],
description: 'Test whether a value is finite, elementwise on collections.',
examples: [
'isFinite(Infinity)',
'isFinite(bigint(3))',
'isFinite([3, -Infinity, -3])'
],
seealso: ['isBounded', 'isNumeric', 'isNaN', 'isNegative', 'isPositive']
}
7 changes: 3 additions & 4 deletions src/expression/node/ConstantNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import { factory } from '../../utils/factory.js'

const name = 'ConstantNode'
const dependencies = [
'Node'
'Node', 'isBounded'
]

export const createConstantNode = /* #__PURE__ */ factory(name, dependencies, ({ Node }) => {
export const createConstantNode = /* #__PURE__ */ factory(name, dependencies, ({ Node, isBounded }) => {
class ConstantNode extends Node {
/**
* A ConstantNode holds a constant value like a number or string.
Expand Down Expand Up @@ -149,8 +149,7 @@ export const createConstantNode = /* #__PURE__ */ factory(name, dependencies, ({

case 'number':
case 'BigNumber': {
const finite = type === 'BigNumber' ? this.value.isFinite() : isFinite(this.value)
if (!finite) {
if (!isBounded(this.value)) {
return (this.value.valueOf() < 0)
? '-\\infty'
: '\\infty'
Expand Down
2 changes: 2 additions & 0 deletions src/factoriesAny.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export { createHasNumericValue } from './function/utils/hasNumericValue.js'
export { createIsPositive } from './function/utils/isPositive.js'
export { createIsZero } from './function/utils/isZero.js'
export { createIsNaN } from './function/utils/isNaN.js'
export { createIsBounded } from './function/utils/isBounded.js'
export { createIsFinite } from './function/utils/isFinite.js'
export { createTypeOf } from './function/utils/typeOf.js'
export { createEqualScalar } from './function/relational/equalScalar.js'
export { createSparseMatrixClass } from './type/matrix/SparseMatrix.js'
Expand Down
2 changes: 2 additions & 0 deletions src/factoriesNumber.js
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,8 @@ export { createHasNumericValue } from './function/utils/hasNumericValue.js'
export const createIsPositive = /* #__PURE__ */ createNumberFactory('isPositive', isPositiveNumber)
export const createIsZero = /* #__PURE__ */ createNumberFactory('isZero', isZeroNumber)
export const createIsNaN = /* #__PURE__ */ createNumberFactory('isNaN', isNaNNumber)
export { createIsBounded } from './function/utils/isBounded.js'
export { createIsFinite } from './function/utils/isFinite.js'
export { createTypeOf } from './function/utils/typeOf.js'
export { createIsPrime } from './function/utils/isPrime.js'
export { createNumeric } from './function/utils/numeric.js'
Expand Down
4 changes: 3 additions & 1 deletion src/function/algebra/simplifyConstant.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const dependencies = [
'config',
'mathWithTransform',
'matrix',
'isBounded',
'?fraction',
'?bignumber',
'AccessorNode',
Expand All @@ -27,6 +28,7 @@ export const createSimplifyConstant = /* #__PURE__ */ factory(name, dependencies
config,
mathWithTransform,
matrix,
isBounded,
fraction,
bignumber,
AccessorNode,
Expand Down Expand Up @@ -141,7 +143,7 @@ export const createSimplifyConstant = /* #__PURE__ */ factory(name, dependencies
// and when both numerator and denominator are small enough
function _exactFraction (n, options) {
const exactFractions = (options && options.exactFractions !== false)
if (exactFractions && isFinite(n) && fraction) {
if (exactFractions && isBounded(n) && fraction) {
const f = fraction(n)
const fractionsLimit = (options && typeof options.fractionsLimit === 'number')
? options.fractionsLimit
Expand Down
6 changes: 5 additions & 1 deletion src/function/arithmetic/nthRoots.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,11 @@ export const createNthRoots = /* #__PURE__ */ factory(name, dependencies, ({ typ
* Calculate the nth roots of a value.
* An nth root of a positive real number A,
* is a positive real solution of the equation "x^root = A".
* This function returns an array of complex values.
* This function returns an array of Complex values.
* Note that currently the precision of Complex numbers are limited
* to the precision of a 64-bit IEEE floating point, so even if the input
* is a BigNumber with greater precision, rounding to 64 bits will occur
* in computing the nth roots.
*
* Syntax:
*
Expand Down
6 changes: 3 additions & 3 deletions src/function/special/zeta.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { factory } from '../../utils/factory.js'

const name = 'zeta'
const dependencies = ['typed', 'config', 'multiply', 'pow', 'divide', 'factorial', 'equal', 'smallerEq', 'isNegative', 'gamma', 'sin', 'subtract', 'add', '?Complex', '?BigNumber', 'pi']
const dependencies = ['typed', 'config', 'multiply', 'pow', 'divide', 'factorial', 'equal', 'smallerEq', 'isBounded', 'isNegative', 'gamma', 'sin', 'subtract', 'add', '?Complex', '?BigNumber', 'pi']

export const createZeta = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, multiply, pow, divide, factorial, equal, smallerEq, isNegative, gamma, sin, subtract, add, Complex, BigNumber, pi }) => {
export const createZeta = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, multiply, pow, divide, factorial, equal, smallerEq, isBounded, isNegative, gamma, sin, subtract, add, Complex, BigNumber, pi }) => {
/**
* Compute the Riemann Zeta function of a value using an infinite series for
* all of the complex plane using Riemann's Functional equation.
Expand Down Expand Up @@ -57,7 +57,7 @@ export const createZeta = /* #__PURE__ */ factory(name, dependencies, ({ typed,
if (equal(s, 1)) {
return createValue(NaN)
}
if (!isFinite(s)) {
if (!isBounded(s)) {
return isNegative(s) ? createValue(NaN) : createValue(1)
}

Expand Down
49 changes: 49 additions & 0 deletions src/function/utils/isBounded.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { factory } from '../../utils/factory.js'

const name = 'isBounded'
const dependencies = ['typed']

export const createIsBounded = /* #__PURE__ */ factory(name, dependencies, ({
typed
}) => {
/**
* Test whether a value is bounded. For scalars, this test is equivalent
* to the isFinite finiteness test. On the other hand, a Matrix or Array
* is defined to be bounded if every entry is finite.
*
* Syntax:
*
* math.isBounded(x)
*
* Examples:
*
* math.isBounded(0) // returns true
* math.isBounded(NaN) // returns false
* math.isBounded(math.bignumber(Infinity)) // returns false
* math.isBounded(math.fraction(1,3)) // returns true
* math.isBounded(math.complex('2 - 4i')) // returns true
* math.isBounded(-10000000000000000n) // returns true
* math.isBounded(undefined) // returns false
* math.isBounded(null) // returns false
* math.isBounded([0.001, -3n, 0]) // returns true
* math.isBounded([2, -Infinity, -3]) // returns false
*
* See also:
*
* isFinite, isNumeric, isPositive, isNegative, isNaN
*
* @param {number | BigNumber | bigint | Complex | Fraction | Unit | Array | Matrix} x Value to be tested
* @return {boolean} Returns true when `x` is bounded.
*/
return typed(name, {
number: n => Number.isFinite(n),
'BigNumber | Complex': x => x.isFinite(),
'bigint | Fraction': () => true,
'null | undefined': () => false,
Unit: typed.referToSelf(self => x => self(x.value)),
'Array | Matrix': typed.referToSelf(self => A => {
if (!Array.isArray(A)) A = A.valueOf()
return A.every(entry => self(entry))
})
})
})
43 changes: 43 additions & 0 deletions src/function/utils/isFinite.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { factory } from '../../utils/factory.js'

const name = 'isFinite'
const dependencies = ['typed', 'isBounded', 'map']

export const createIsFinite = /* #__PURE__ */ factory(name, dependencies, ({
typed, isBounded, map
}) => {
/**
* Test whether a value is finite.
*
* Operates elementwise on Array and Matrix values. To test if all entries
* of an Array or Matrix are finite, use isBounded.
*
* Syntax:
*
* math.isFinite(x)
*
* Examples:
*
* math.isFinite(0) // returns true
* math.isFinite(NaN) // returns false
* math.isFinite(math.bignumber(Infinity)) // returns false
* math.isFinite(math.fraction(1,3)) // returns true
* math.isFinite(math.complex('2 - 4i')) // returns true
* math.isFinite(-10000000000000000n) // returns true
* math.isFinite(undefined) // returns false
* math.isFinite(null) // returns false
* math.isFinite([0.001, -3n, 0]) // Array [true, true, true]
* math.isFinite([2, -Infinity, -3]) // Array [true, false, true]
*
* See also:
*
* isBounded isNumeric, isPositive, isNegative, isNaN
*
* @param {number | BigNumber | bigint | Complex | Fraction | Unit | Array | Matrix} x Value to be tested
* @return {boolean | Array | Matrix}
*/
return typed(name, {
'Array | Matrix': A => map(A, isBounded),
any: x => isBounded(x)
})
})
2 changes: 1 addition & 1 deletion src/json/replacer.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const createReplacer = /* #__PURE__ */ factory(name, dependencies, () =>
*/
return function replacer (key, value) {
// the numeric values Infinitiy, -Infinity, and NaN cannot be serialized to JSON
if (typeof value === 'number' && (!isFinite(value) || isNaN(value))) {
if (typeof value === 'number' && (!Number.isFinite(value) || isNaN(value))) {
return {
mathjs: 'number',
value: String(value)
Expand Down
4 changes: 2 additions & 2 deletions src/plain/number/probability.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export function gammaNumber (n) {

if (isInteger(n)) {
if (n <= 0) {
return isFinite(n) ? Infinity : NaN
return Number.isFinite(n) ? Infinity : NaN
}

if (n > 171) {
Expand Down Expand Up @@ -91,7 +91,7 @@ export const lgammaSeries = [
export function lgammaNumber (n) {
if (n < 0) return NaN
if (n === 0) return Infinity
if (!isFinite(n)) return n
if (!Number.isFinite(n)) return n

if (n < 0.5) {
// Use Euler's reflection formula:
Expand Down
2 changes: 1 addition & 1 deletion src/plain/number/trigonometry.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export function acotNumber (x) {
acotNumber.signature = n1

export function acothNumber (x) {
return isFinite(x)
return Number.isFinite(x)
? (Math.log((x + 1) / x) + Math.log(x / (x - 1))) / 2
: 0
}
Expand Down
2 changes: 1 addition & 1 deletion src/type/fraction/function/fraction.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export const createFraction = /* #__PURE__ */ factory(name, dependencies, ({ typ
*/
return typed('fraction', {
number: function (x) {
if (!isFinite(x) || isNaN(x)) {
if (!Number.isFinite(x) || isNaN(x)) {
throw new Error(x + ' cannot be represented as a fraction')
}

Expand Down
14 changes: 7 additions & 7 deletions src/utils/number.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export function isInteger (value) {
return true
}

return isFinite(value)
return Number.isFinite(value)
? (value === Math.round(value))
: false
}
Expand Down Expand Up @@ -111,7 +111,7 @@ export const cbrt = Math.cbrt || function cbrt (x) {
x = -x
}

if (isFinite(x)) {
if (Number.isFinite(x)) {
result = Math.exp(Math.log(x) / 3)
// from https://en.wikipedia.org/wiki/Cube_root#Numerical_methods
result = (x / (result * result) + (2 * result)) / 3
Expand Down Expand Up @@ -396,7 +396,7 @@ export function splitNumber (value) {
* @param {number} [precision] Optional number of significant figures to return.
*/
export function toEngineering (value, precision) {
if (isNaN(value) || !isFinite(value)) {
if (isNaN(value) || !Number.isFinite(value)) {
return String(value)
}

Expand Down Expand Up @@ -451,7 +451,7 @@ export function toEngineering (value, precision) {
* decimal point. null by default.
*/
export function toFixed (value, precision) {
if (isNaN(value) || !isFinite(value)) {
if (isNaN(value) || !Number.isFinite(value)) {
return String(value)
}

Expand Down Expand Up @@ -490,7 +490,7 @@ export function toFixed (value, precision) {
* is used.
*/
export function toExponential (value, precision) {
if (isNaN(value) || !isFinite(value)) {
if (isNaN(value) || !Number.isFinite(Number(value))) {
return String(value)
}

Expand Down Expand Up @@ -522,7 +522,7 @@ export function toExponential (value, precision) {
* @return {string}
*/
export function toPrecision (value, precision, options) {
if (isNaN(value) || !isFinite(value)) {
if (isNaN(value) || !Number.isFinite(value)) {
return String(value)
}

Expand Down Expand Up @@ -670,7 +670,7 @@ export function nearlyEqual (a, b, relTol = 1e-8, absTol = 0) {
return false
}

if (!isFinite(a) || !isFinite(b)) {
if (!Number.isFinite(a) || !Number.isFinite(b)) {
return a === b
}

Expand Down
Loading