Skip to content

Commit fcca5b3

Browse files
authored
Merge branch 'develop' into fix/percent-additions
2 parents 24c37dc + f211411 commit fcca5b3

9 files changed

Lines changed: 69 additions & 42 deletions

File tree

AUTHORS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ kyle-compute <kyle@intelvis.ai>
278278
DongKwanKho <70864292+dodokw@users.noreply.github.com>
279279
Ikem Peter <ikempeter2020@gmail.com>
280280
Josh Kelley <joshkel@gmail.com>
281-
Nils Dietrich <nils.dietrich@enervance.de>
282281
Richard Taylor <richard.taylor@claconnect.com>
282+
NilsDietrich <61544566+NilsDietrich@users.noreply.github.com>
283283

284284
# Generated by tools/update-authors.js

HISTORY.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
Thanks @NilsDietrich.
1111
- Fix: #3564 Avoid error throws when mapping/filtering empty arrays/matrices.
1212
(#3567). Thanks @richardt-cla.
13+
- Fix: #3574 respect tolerances in function `isInteger` (#3575).
14+
Thanks @gwhitney.
15+
- Fix: #3562 serializing units missing an internal property (#3572).
1316

1417
# 2025-10-10, 15.0.0
1518

src/function/relational/equal.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,14 @@ const dependencies = [
1010
'matrix',
1111
'equalScalar',
1212
'DenseMatrix',
13-
'concat',
1413
'SparseMatrix'
1514
]
1615

1716
export const createEqual = /* #__PURE__ */ factory(name, dependencies, ({ typed, matrix, equalScalar, DenseMatrix, concat, SparseMatrix }) => {
1817
const matAlgo03xDSf = createMatAlgo03xDSf({ typed })
1918
const matAlgo07xSSf = createMatAlgo07xSSf({ typed, SparseMatrix })
2019
const matAlgo12xSfs = createMatAlgo12xSfs({ typed, DenseMatrix })
21-
const matrixAlgorithmSuite = createMatrixAlgorithmSuite({ typed, matrix, concat })
20+
const matrixAlgorithmSuite = createMatrixAlgorithmSuite({ typed, matrix })
2221

2322
/**
2423
* Test whether two values are equal.

src/function/utils/isInteger.js

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { deepMap } from '../../utils/collection.js'
2-
import { isInteger as isIntegerNumber } from '../../utils/number.js'
32
import { factory } from '../../utils/factory.js'
43

54
const name = 'isInteger'
6-
const dependencies = ['typed']
5+
const dependencies = ['typed', 'equal']
76

8-
export const createIsInteger = /* #__PURE__ */ factory(name, dependencies, ({ typed }) => {
7+
export const createIsInteger = /* #__PURE__ */ factory(name, dependencies, ({
8+
typed, equal
9+
}) => {
910
/**
1011
* Test whether a value is an integer number.
1112
* The function supports `number`, `BigNumber`, and `Fraction`.
@@ -36,19 +37,13 @@ export const createIsInteger = /* #__PURE__ */ factory(name, dependencies, ({ ty
3637
* Throws an error in case of an unknown data type.
3738
*/
3839
return typed(name, {
39-
number: isIntegerNumber, // TODO: what to do with isInteger(add(0.1, 0.2)) ?
40+
number: n => Number.isFinite(n) ? equal(n, Math.round(n)) : false,
4041

41-
BigNumber: function (x) {
42-
return x.isInt()
43-
},
42+
BigNumber: b => b.isFinite() ? equal(b.round(), b) : false,
4443

45-
bigint: function (x) {
46-
return true
47-
},
44+
bigint: b => true,
4845

49-
Fraction: function (x) {
50-
return x.d === 1n
51-
},
46+
Fraction: r => r.d === 1n,
5247

5348
'Array | Matrix': typed.referToSelf(self => x => deepMap(x, self))
5449
})

src/type/unit/Unit.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ const dependencies = [
2020
'equal',
2121
'isNumeric',
2222
'format',
23-
'toBest',
2423
'number',
2524
'Complex',
2625
'BigNumber',
@@ -41,13 +40,15 @@ export const createUnitClass = /* #__PURE__ */ factory(name, dependencies, ({
4140
equal,
4241
isNumeric,
4342
format,
44-
toBest,
4543
number,
4644
Complex,
4745
BigNumber,
4846
Fraction
4947
}) => {
5048
const toNumber = number
49+
const fixPrefixDefault = false
50+
const skipAutomaticSimplificationDefault = true
51+
5152
/**
5253
* A unit can be constructed in the following ways:
5354
*
@@ -76,13 +77,13 @@ export const createUnitClass = /* #__PURE__ */ factory(name, dependencies, ({
7677
throw new TypeError('First parameter in Unit constructor must be number, BigNumber, Fraction, Complex, or undefined')
7778
}
7879

79-
this.fixPrefix = false // if true, function format will not search for the
80+
this.fixPrefix = fixPrefixDefault // if true, function format will not search for the
8081
// best prefix but leave it as initially provided.
8182
// fixPrefix is set true by the method Unit.to
8283

8384
// The justification behind this is that if the constructor is explicitly called,
8485
// the caller wishes the units to be returned exactly as supplied.
85-
this.skipAutomaticSimplification = true
86+
this.skipAutomaticSimplification = skipAutomaticSimplificationDefault
8687

8788
if (valuelessUnit === undefined) {
8889
this.units = []
@@ -916,14 +917,15 @@ export const createUnitClass = /* #__PURE__ */ factory(name, dependencies, ({
916917
* Get a JSON representation of the unit
917918
* @memberof Unit
918919
* @returns {Object} Returns a JSON object structured as:
919-
* `{"mathjs": "Unit", "value": 2, "unit": "cm", "fixPrefix": false}`
920+
* `{"mathjs": "Unit", "value": 2, "unit": "cm", "fixPrefix": false, "skipSimp": true}`
920921
*/
921922
Unit.prototype.toJSON = function () {
922923
return {
923924
mathjs: 'Unit',
924925
value: this._denormalize(this.value),
925926
unit: this.units.length > 0 ? this.formatUnits() : null,
926-
fixPrefix: this.fixPrefix
927+
fixPrefix: this.fixPrefix,
928+
skipSimp: this.skipAutomaticSimplification
927929
}
928930
}
929931

@@ -936,7 +938,8 @@ export const createUnitClass = /* #__PURE__ */ factory(name, dependencies, ({
936938
*/
937939
Unit.fromJSON = function (json) {
938940
const unit = new Unit(json.value, json.unit ?? undefined)
939-
unit.fixPrefix = json.fixPrefix || false
941+
unit.fixPrefix = json.fixPrefix ?? fixPrefixDefault
942+
unit.skipAutomaticSimplification = json.skipSimp ?? skipAutomaticSimplificationDefault
940943
return unit
941944
}
942945

test/unit-tests/function/utils/isInteger.test.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ describe('isInteger', function () {
1414
assert.strictEqual(isInteger(Infinity), false)
1515
assert.strictEqual(isInteger(-Infinity), false)
1616
assert.strictEqual(isInteger(NaN), false)
17-
assert.strictEqual(isInteger(0.1 + 0.2), false) // TODO: what to do with round off errors?
17+
assert.strictEqual(isInteger(0.1 + 0.2), false)
18+
assert.strictEqual(isInteger((0.1 + 0.2) * 10), true)
19+
assert.strictEqual(isInteger((0.1 + 0.2) * 10 - 3), true)
1820
})
1921

2022
it('should test whether a bigint is an integer', function () {
@@ -37,6 +39,8 @@ describe('isInteger', function () {
3739
assert.strictEqual(isInteger(bignumber(Infinity)), false)
3840
assert.strictEqual(isInteger(bignumber(-Infinity)), false)
3941
assert.strictEqual(isInteger(bignumber(NaN)), false)
42+
assert.strictEqual(isInteger(bignumber((0.1 + 0.2) * 10)), true)
43+
assert.strictEqual(isInteger(bignumber((0.1 + 0.2) * 10 - 3)), true)
4044
})
4145

4246
it('should test whether a Fraction is an integer', function () {

test/unit-tests/json/replacer.test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,21 +74,21 @@ describe('replacer', function () {
7474

7575
it('should stringify a Unit', function () {
7676
const u = new math.Unit(5, 'cm')
77-
const json = '{"mathjs":"Unit","value":5,"unit":"cm","fixPrefix":false}'
77+
const json = '{"mathjs":"Unit","value":5,"unit":"cm","fixPrefix":false,"skipSimp":true}'
7878
assert.deepStrictEqual(JSON.stringify(u), json)
7979
assert.deepStrictEqual(JSON.stringify(u, replacer), json)
8080
})
8181

8282
it('should stringify a Unit with a value only', function () {
8383
const u = new math.Unit(5)
84-
const json = '{"mathjs":"Unit","value":5,"unit":null,"fixPrefix":false}'
84+
const json = '{"mathjs":"Unit","value":5,"unit":null,"fixPrefix":false,"skipSimp":true}'
8585
assert.deepStrictEqual(JSON.stringify(u), json)
8686
assert.deepStrictEqual(JSON.stringify(u, replacer), json)
8787
})
8888

8989
it('should stringify a Unit without a value', function () {
9090
const u = new math.Unit(null, 'cm')
91-
const json = '{"mathjs":"Unit","value":null,"unit":"cm","fixPrefix":false}'
91+
const json = '{"mathjs":"Unit","value":null,"unit":"cm","fixPrefix":false,"skipSimp":true}'
9292
assert.deepStrictEqual(JSON.stringify(u), json)
9393
assert.deepStrictEqual(JSON.stringify(u, replacer), json)
9494
})

test/unit-tests/json/reviver.test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ describe('reviver', function () {
7979
})
8080

8181
it('should parse a stringified Unit', function () {
82-
const json = '{"mathjs":"Unit","value":5,"unit":"cm","fixPrefix":false}'
82+
const json = '{"mathjs":"Unit","value":5,"unit":"cm","fixPrefix":false,"skipSimp":true}'
8383
const u = new math.Unit(5, 'cm')
8484

8585
const obj = JSON.parse(json, reviver)
@@ -89,7 +89,7 @@ describe('reviver', function () {
8989
})
9090

9191
it('should parse a stringified Unit with a value only', function () {
92-
const json = '{"mathjs":"Unit","value":5,"unit":null,"fixPrefix":false}'
92+
const json = '{"mathjs":"Unit","value":5,"unit":null,"fixPrefix":false,"skipSimp":true}'
9393
const u = new math.Unit(5)
9494

9595
const obj = JSON.parse(json, reviver)
@@ -99,7 +99,7 @@ describe('reviver', function () {
9999
})
100100

101101
it('should parse a stringified Unit without a value', function () {
102-
const json = '{"mathjs":"Unit","value":null,"unit":"cm","fixPrefix":false}'
102+
const json = '{"mathjs":"Unit","value":null,"unit":"cm","fixPrefix":false,"skipSimp":true}'
103103
const u = new math.Unit(null, 'cm')
104104

105105
const obj = JSON.parse(json, reviver)

test/unit-tests/type/unit/Unit.test.js

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -651,64 +651,87 @@ describe('Unit', function () {
651651
describe('json', function () {
652652
it('toJSON', function () {
653653
assert.deepStrictEqual(new Unit(5, 'cm').toJSON(),
654-
{ mathjs: 'Unit', value: 5, unit: 'cm', fixPrefix: false })
654+
{ mathjs: 'Unit', value: 5, unit: 'cm', fixPrefix: false, skipSimp: true })
655655
assert.deepStrictEqual(new Unit(5, 'cm').to('mm').toJSON(),
656-
{ mathjs: 'Unit', value: 50, unit: 'mm', fixPrefix: true })
656+
{ mathjs: 'Unit', value: 50, unit: 'mm', fixPrefix: true, skipSimp: true })
657657
assert.deepStrictEqual(new Unit(5, 'kN').to('kg m s ^ -2').toJSON(),
658-
{ mathjs: 'Unit', value: 5000, unit: '(kg m) / s^2', fixPrefix: true })
658+
{ mathjs: 'Unit', value: 5000, unit: '(kg m) / s^2', fixPrefix: true, skipSimp: true })
659659
assert.deepStrictEqual(new Unit(math.fraction(0.375), 'cm').toJSON(),
660660
{
661661
mathjs: 'Unit',
662662
value: math.fraction(0.375), // Note that value is not serialized at this point, that will be done by JSON.stringify
663663
unit: 'cm',
664-
fixPrefix: false
664+
fixPrefix: false,
665+
skipSimp: true
665666
})
666667
approxDeepEqual(new Unit(math.complex(2, 4), 'g').toJSON(),
667668
{
668669
mathjs: 'Unit',
669670
value: math.complex(2, 4),
670671
unit: 'g',
671-
fixPrefix: false
672+
fixPrefix: false,
673+
skipSimp: true
674+
})
675+
676+
assert.deepStrictEqual(math.evaluate('2 kg * 3 in^2').toJSON(),
677+
{
678+
mathjs: 'Unit',
679+
value: 6,
680+
unit: 'kg in^2',
681+
fixPrefix: false,
682+
skipSimp: false
672683
})
673684

674685
const str = JSON.stringify(new Unit(math.fraction(0.375), 'cm'))
675-
assert.deepStrictEqual(str, '{"mathjs":"Unit","value":{"mathjs":"Fraction","n":"3","d":"8"},"unit":"cm","fixPrefix":false}')
686+
assert.deepStrictEqual(str, '{"mathjs":"Unit","value":{"mathjs":"Fraction","n":"3","d":"8"},"unit":"cm","fixPrefix":false,"skipSimp":true}')
676687

677688
const cmpx = JSON.stringify(new Unit(math.complex(2, 4), 'g'))
678-
assert.strictEqual(cmpx, '{"mathjs":"Unit","value":{"mathjs":"Complex","re":2,"im":4},"unit":"g","fixPrefix":false}')
689+
assert.strictEqual(cmpx, '{"mathjs":"Unit","value":{"mathjs":"Complex","re":2,"im":4},"unit":"g","fixPrefix":false,"skipSimp":true}')
679690
})
680691

681692
it('fromJSON', function () {
682693
const u1 = new Unit(5, 'cm')
683-
const u2 = Unit.fromJSON({ mathjs: 'Unit', value: 5, unit: 'cm', fixPrefix: false })
694+
const u2 = Unit.fromJSON({ mathjs: 'Unit', value: 5, unit: 'cm', fixPrefix: false, skipSimp: true })
684695
assert.ok(u2 instanceof Unit)
685696
assert.deepStrictEqual(u2, u1)
686697

687698
const u3 = new Unit(5, 'cm').to('mm')
688-
const u4 = Unit.fromJSON({ mathjs: 'Unit', value: 50, unit: 'mm', fixPrefix: true })
699+
const u4 = Unit.fromJSON({ mathjs: 'Unit', value: 50, unit: 'mm', fixPrefix: true, skipSimp: true })
689700
assert.ok(u4 instanceof Unit)
690701
assert.deepStrictEqual(u4, u3)
691702

692703
const u5 = new Unit(5, 'kN').to('kg m/s^2')
693-
const u6 = Unit.fromJSON({ mathjs: 'Unit', value: 5000, unit: 'kg m s^-2', fixPrefix: true })
704+
const u6 = Unit.fromJSON({ mathjs: 'Unit', value: 5000, unit: 'kg m s^-2', fixPrefix: true, skipSimp: true })
694705
assert.ok(u6 instanceof Unit)
695706
assert.deepStrictEqual(u5, u6)
696707

697708
const u7 = Unit.fromJSON({
698709
mathjs: 'Unit',
699710
value: math.fraction(0.375), // Note that value is already a Fraction at this point, that will be done by JSON.parse(str, reviver)
700711
unit: 'cm',
701-
fixPrefix: false
712+
fixPrefix: false,
713+
skipSimp: true
702714
})
703715
assert.deepStrictEqual(u7, new Unit(math.fraction(0.375), 'cm'))
704716

705717
const u8 = Unit.fromJSON({
706718
mathjs: 'Unit',
707719
value: math.complex(2, 4),
708720
unit: 'g',
709-
fixPrefix: false
721+
fixPrefix: false,
722+
skipSimp: true
710723
})
711724
assert.deepStrictEqual(u8, new Unit(math.complex(2, 4), 'g'))
725+
726+
const u9 = Unit.fromJSON({
727+
mathjs: 'Unit',
728+
value: 6,
729+
unit: 'kg in^2',
730+
fixPrefix: false,
731+
skipSimp: false
732+
})
733+
const u10 = math.evaluate('2 kg * 3 in^2')
734+
assert.deepStrictEqual(u9, u10)
712735
})
713736

714737
it('toJSON -> fromJSON should recover an "equal" unit', function () {

0 commit comments

Comments
 (0)