Skip to content

Commit 7e056f7

Browse files
authored
Merge branch 'develop' into array-flatten-infinity
2 parents 94b7f34 + 393cc66 commit 7e056f7

File tree

28 files changed

+1042
-755
lines changed

28 files changed

+1042
-755
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,5 +259,6 @@ Neeraj Kumawat <42885320+nkumawat34@users.noreply.github.com>
259259
Emmanuel Ferdman <emmanuelferdman@gmail.com>
260260
Paul Korzhyk <paul.korzhyk@gmail.com>
261261
Francois <819179+fchu@users.noreply.github.com>
262+
witer33 <34513257+witer33@users.noreply.github.com>
262263

263264
# Generated by tools/update-authors.js

HISTORY.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
# History
22

3-
# unpublished changes since 14.0.1
3+
# 2025-01-24, 14.1.0
44

5+
- Feat: implement `bigint` support in functions `log`, `log2`, `log10`,
6+
`larger`, `smaller`, `max`, `min` (#3345). Thanks @gwhitney.
7+
- Fix: #3342 hexadecimal input not turned into a `bigint` (#3348).
8+
- Fix `randomInt()` not working (#3345).
59
- Docs: fixed description of `sign` in the embedded docs (#3338).
610
Thanks @witer33.
711

package-lock.json

Lines changed: 788 additions & 667 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mathjs",
3-
"version": "14.0.1",
3+
"version": "14.1.0",
44
"description": "Math.js is an extensive math library for JavaScript and Node.js. It features a flexible expression parser with support for symbolic computation, comes with a large set of built-in functions and constants, and offers an integrated solution to work with different data types like numbers, big numbers, complex numbers, fractions, units, and matrices.",
55
"author": "Jos de Jong <wjosdejong@gmail.com> (https://github.com/josdejong)",
66
"homepage": "https://mathjs.org",
@@ -45,13 +45,13 @@
4545
"@babel/register": "7.25.9",
4646
"@types/assert": "1.5.11",
4747
"@types/mocha": "10.0.10",
48-
"@typescript-eslint/eslint-plugin": "8.18.0",
49-
"@typescript-eslint/parser": "8.18.0",
48+
"@typescript-eslint/eslint-plugin": "8.21.0",
49+
"@typescript-eslint/parser": "8.21.0",
5050
"assert": "2.1.0",
5151
"babel-loader": "9.2.1",
5252
"c8": "10.1.3",
5353
"codecov": "3.8.3",
54-
"core-js": "3.39.0",
54+
"core-js": "3.40.0",
5555
"del": "8.0.0",
5656
"dtslint": "4.2.1",
5757
"eigen": "0.2.2",
@@ -61,12 +61,12 @@
6161
"eslint-plugin-import": "2.31.0",
6262
"eslint-plugin-mocha": "10.5.0",
6363
"eslint-plugin-n": "16.6.2",
64-
"eslint-plugin-prettier": "5.2.1",
64+
"eslint-plugin-prettier": "5.2.3",
6565
"eslint-plugin-promise": "6.6.0",
6666
"expect-type": "1.1.0",
6767
"expr-eval": "2.0.2",
6868
"fancy-log": "2.0.0",
69-
"glob": "11.0.0",
69+
"glob": "11.0.1",
7070
"gulp": "5.0.0",
7171
"gulp-babel": "8.0.0",
7272
"handlebars": "4.7.8",
@@ -79,7 +79,7 @@
7979
"karma-webdriver-launcher": "1.0.8",
8080
"karma-webpack": "5.0.1",
8181
"mkdirp": "3.0.1",
82-
"mocha": "11.0.1",
82+
"mocha": "11.1.0",
8383
"mocha-junit-reporter": "2.2.1",
8484
"ndarray": "1.0.19",
8585
"ndarray-determinant": "1.0.0",
@@ -91,9 +91,9 @@
9191
"process": "0.11.10",
9292
"sinon": "19.0.2",
9393
"sylvester": "0.0.21",
94-
"tinybench": "3.0.7",
94+
"tinybench": "3.1.0",
9595
"ts-node": "10.9.2",
96-
"typescript": "5.7.2",
96+
"typescript": "5.7.3",
9797
"webpack": "5.97.1",
9898
"zeros": "1.0.0"
9999
},

src/function/arithmetic/log.js

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { factory } from '../../utils/factory.js'
2+
import { promoteLogarithm } from '../../utils/bigint.js'
23
import { logNumber } from '../../plain/number/index.js'
34

45
const name = 'log'
56
const dependencies = ['config', 'typed', 'typeOf', 'divideScalar', 'Complex']
7+
const nlg16 = Math.log(16)
68

79
export const createLog = /* #__PURE__ */ factory(name, dependencies, ({ typed, typeOf, config, divideScalar, Complex }) => {
810
/**
@@ -40,26 +42,34 @@ export const createLog = /* #__PURE__ */ factory(name, dependencies, ({ typed, t
4042
* @return {number | BigNumber | Fraction | Complex}
4143
* Returns the logarithm of `x`
4244
*/
45+
function complexLog (c) {
46+
return c.log()
47+
}
48+
49+
function complexLogNumber (x) {
50+
return complexLog(new Complex(x, 0))
51+
}
52+
4353
return typed(name, {
4454
number: function (x) {
4555
if (x >= 0 || config.predictable) {
4656
return logNumber(x)
4757
} else {
4858
// negative value -> complex value computation
49-
return new Complex(x, 0).log()
59+
return complexLogNumber(x)
5060
}
5161
},
5262

53-
Complex: function (x) {
54-
return x.log()
55-
},
63+
bigint: promoteLogarithm(nlg16, logNumber, config, complexLogNumber),
64+
65+
Complex: complexLog,
5666

5767
BigNumber: function (x) {
5868
if (!x.isNegative() || config.predictable) {
5969
return x.ln()
6070
} else {
6171
// downgrade to number, return Complex valued result
62-
return new Complex(x.toNumber(), 0).log()
72+
return complexLogNumber(x.toNumber())
6373
}
6474
},
6575

src/function/arithmetic/log10.js

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
import { factory } from '../../utils/factory.js'
2-
import { deepMap } from '../../utils/collection.js'
31
import { log10Number } from '../../plain/number/index.js'
2+
import { promoteLogarithm } from '../../utils/bigint.js'
3+
import { deepMap } from '../../utils/collection.js'
4+
import { factory } from '../../utils/factory.js'
45

56
const name = 'log10'
67
const dependencies = ['typed', 'config', 'Complex']
8+
const log16 = log10Number(16)
79

810
export const createLog10 = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, Complex }) => {
911
/**
@@ -31,26 +33,34 @@ export const createLog10 = /* #__PURE__ */ factory(name, dependencies, ({ typed,
3133
* @return {number | BigNumber | Complex | Array | Matrix}
3234
* Returns the 10-base logarithm of `x`
3335
*/
36+
37+
function complexLog (c) {
38+
return c.log().div(Math.LN10)
39+
}
40+
41+
function complexLogNumber (x) {
42+
return complexLog(new Complex(x, 0))
43+
}
3444
return typed(name, {
3545
number: function (x) {
3646
if (x >= 0 || config.predictable) {
3747
return log10Number(x)
3848
} else {
3949
// negative value -> complex value computation
40-
return new Complex(x, 0).log().div(Math.LN10)
50+
return complexLogNumber(x)
4151
}
4252
},
4353

44-
Complex: function (x) {
45-
return new Complex(x).log().div(Math.LN10)
46-
},
54+
bigint: promoteLogarithm(log16, log10Number, config, complexLogNumber),
55+
56+
Complex: complexLog,
4757

4858
BigNumber: function (x) {
4959
if (!x.isNegative() || config.predictable) {
5060
return x.log()
5161
} else {
5262
// downgrade to number, return Complex valued result
53-
return new Complex(x.toNumber(), 0).log().div(Math.LN10)
63+
return complexLogNumber(x.toNumber())
5464
}
5565
},
5666

src/function/arithmetic/log2.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { factory } from '../../utils/factory.js'
2-
import { deepMap } from '../../utils/collection.js'
31
import { log2Number } from '../../plain/number/index.js'
2+
import { promoteLogarithm } from '../../utils/bigint.js'
3+
import { deepMap } from '../../utils/collection.js'
4+
import { factory } from '../../utils/factory.js'
45

56
const name = 'log2'
67
const dependencies = ['typed', 'config', 'Complex']
@@ -31,24 +32,30 @@ export const createLog2 = /* #__PURE__ */ factory(name, dependencies, ({ typed,
3132
* @return {number | BigNumber | Complex | Array | Matrix}
3233
* Returns the 2-base logarithm of `x`
3334
*/
35+
function complexLog2Number (x) {
36+
return _log2Complex(new Complex(x, 0))
37+
}
38+
3439
return typed(name, {
3540
number: function (x) {
3641
if (x >= 0 || config.predictable) {
3742
return log2Number(x)
3843
} else {
3944
// negative value -> complex value computation
40-
return _log2Complex(new Complex(x, 0))
45+
return complexLog2Number(x)
4146
}
4247
},
4348

49+
bigint: promoteLogarithm(4, log2Number, config, complexLog2Number),
50+
4451
Complex: _log2Complex,
4552

4653
BigNumber: function (x) {
4754
if (!x.isNegative() || config.predictable) {
4855
return x.log(2)
4956
} else {
5057
// downgrade to number, return Complex valued result
51-
return _log2Complex(new Complex(x.toNumber(), 0))
58+
return complexLog2Number(x.toNumber())
5259
}
5360
},
5461

src/function/probability/randomInt.js

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import { createRng } from './util/seededRNG.js'
44
import { isMatrix } from '../../utils/is.js'
55

66
const name = 'randomInt'
7-
const dependencies = ['typed', 'config', '?on']
7+
const dependencies = ['typed', 'config', 'log2', '?on']
88

9-
export const createRandomInt = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, on }) => {
9+
const simpleCutoff = 2n ** 30n
10+
11+
export const createRandomInt = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, log2, on }) => {
1012
// seeded pseudo random number generator
1113
let rng = createRng(config.randomSeed)
1214

@@ -24,7 +26,7 @@ export const createRandomInt = /* #__PURE__ */ factory(name, dependencies, ({ ty
2426
*
2527
* Syntax:
2628
*
27-
* math.randomInt() // generate a random integer between 0 and 1
29+
* math.randomInt() // generate either 0 or 1, randomly
2830
* math.randomInt(max) // generate a random integer between 0 and max
2931
* math.randomInt(min, max) // generate a random integer between min and max
3032
* math.randomInt(size) // generate a matrix with random integer between 0 and 1
@@ -48,9 +50,11 @@ export const createRandomInt = /* #__PURE__ */ factory(name, dependencies, ({ ty
4850
* @return {number | Array | Matrix} A random integer value
4951
*/
5052
return typed(name, {
51-
'': () => _randomInt(0, 1),
53+
'': () => _randomInt(0, 2),
5254
number: (max) => _randomInt(0, max),
5355
'number, number': (min, max) => _randomInt(min, max),
56+
bigint: (max) => _randomBigint(0n, max),
57+
'bigint, bigint': _randomBigint,
5458
'Array | Matrix': (size) => _randomIntMatrix(size, 0, 1),
5559
'Array | Matrix, number': (size, max) => _randomIntMatrix(size, 0, max),
5660
'Array | Matrix, number, number': (size, min, max) => _randomIntMatrix(size, min, max)
@@ -64,4 +68,23 @@ export const createRandomInt = /* #__PURE__ */ factory(name, dependencies, ({ ty
6468
function _randomInt (min, max) {
6569
return Math.floor(min + rng() * (max - min))
6670
}
71+
72+
function _randomBigint (min, max) {
73+
const width = max - min // number of choices
74+
if (width <= simpleCutoff) { // do it with number type
75+
return min + BigInt(_randomInt(0, Number(width)))
76+
}
77+
// Too big to choose accurately that way. Instead, choose the correct
78+
// number of random bits to cover the width, and repeat until the
79+
// resulting number falls within the width
80+
const bits = log2(width)
81+
let picked = width
82+
while (picked >= width) {
83+
picked = 0n
84+
for (let i = 0; i < bits; ++i) {
85+
picked = 2n * picked + ((rng() < 0.5) ? 0n : 1n)
86+
}
87+
}
88+
return min + picked
89+
}
6790
})

src/function/relational/larger.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@ const name = 'larger'
1111
const dependencies = [
1212
'typed',
1313
'config',
14+
'bignumber',
1415
'matrix',
1516
'DenseMatrix',
1617
'concat',
1718
'SparseMatrix'
1819
]
1920

20-
export const createLarger = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, matrix, DenseMatrix, concat, SparseMatrix }) => {
21+
export const createLarger = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, bignumber, matrix, DenseMatrix, concat, SparseMatrix }) => {
2122
const matAlgo03xDSf = createMatAlgo03xDSf({ typed })
2223
const matAlgo07xSSf = createMatAlgo07xSSf({ typed, SparseMatrix })
2324
const matAlgo12xSfs = createMatAlgo12xSfs({ typed, DenseMatrix })
@@ -55,20 +56,30 @@ export const createLarger = /* #__PURE__ */ factory(name, dependencies, ({ typed
5556
* @param {number | BigNumber | bigint | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare
5657
* @return {boolean | Array | Matrix} Returns true when the x is larger than y, else returns false
5758
*/
59+
function bignumLarger (x, y) {
60+
return x.gt(y) && !bigNearlyEqual(x, y, config.relTol, config.absTol)
61+
}
62+
5863
return typed(
5964
name,
6065
createLargerNumber({ typed, config }),
6166
{
6267
'boolean, boolean': (x, y) => x > y,
6368

64-
'BigNumber, BigNumber': function (x, y) {
65-
return x.gt(y) && !bigNearlyEqual(x, y, config.relTol, config.absTol)
66-
},
69+
'BigNumber, BigNumber': bignumLarger,
6770

6871
'bigint, bigint': (x, y) => x > y,
6972

7073
'Fraction, Fraction': (x, y) => (x.compare(y) === 1),
7174

75+
'Fraction, BigNumber': function (x, y) {
76+
return bignumLarger(bignumber(x), y)
77+
},
78+
79+
'BigNumber, Fraction': function (x, y) {
80+
return bignumLarger(x, bignumber(y))
81+
},
82+
7283
'Complex, Complex': function () {
7384
throw new TypeError('No ordering relation is defined for complex numbers')
7485
}

src/function/relational/smaller.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@ const name = 'smaller'
1111
const dependencies = [
1212
'typed',
1313
'config',
14+
'bignumber',
1415
'matrix',
1516
'DenseMatrix',
1617
'concat',
1718
'SparseMatrix'
1819
]
1920

20-
export const createSmaller = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, matrix, DenseMatrix, concat, SparseMatrix }) => {
21+
export const createSmaller = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, bignumber, matrix, DenseMatrix, concat, SparseMatrix }) => {
2122
const matAlgo03xDSf = createMatAlgo03xDSf({ typed })
2223
const matAlgo07xSSf = createMatAlgo07xSSf({ typed, SparseMatrix })
2324
const matAlgo12xSfs = createMatAlgo12xSfs({ typed, DenseMatrix })
@@ -55,20 +56,30 @@ export const createSmaller = /* #__PURE__ */ factory(name, dependencies, ({ type
5556
* @param {number | BigNumber | bigint | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare
5657
* @return {boolean | Array | Matrix} Returns true when the x is smaller than y, else returns false
5758
*/
59+
function bignumSmaller (x, y) {
60+
return x.lt(y) && !bigNearlyEqual(x, y, config.relTol, config.absTol)
61+
}
62+
5863
return typed(
5964
name,
6065
createSmallerNumber({ typed, config }),
6166
{
6267
'boolean, boolean': (x, y) => x < y,
6368

64-
'BigNumber, BigNumber': function (x, y) {
65-
return x.lt(y) && !bigNearlyEqual(x, y, config.relTol, config.absTol)
66-
},
69+
'BigNumber, BigNumber': bignumSmaller,
6770

6871
'bigint, bigint': (x, y) => x < y,
6972

7073
'Fraction, Fraction': (x, y) => (x.compare(y) === -1),
7174

75+
'Fraction, BigNumber': function (x, y) {
76+
return bignumSmaller(bignumber(x), y)
77+
},
78+
79+
'BigNumber, Fraction': function (x, y) {
80+
return bignumSmaller(x, bignumber(y))
81+
},
82+
7283
'Complex, Complex': function (x, y) {
7384
throw new TypeError('No ordering relation is defined for complex numbers')
7485
}

0 commit comments

Comments
 (0)