Skip to content

Commit 82074e8

Browse files
authored
fix: Type declarations for rounding functions (#2539)
This is a sequel to #2531. Uniformizes the signatures of ceil, fix, floor, and round, and updates the TypeScript declarations to match. Adds the optional "number of places" argument to the chain versions of ceil, fix, and floor. Adds TypeScript tests for all rounding functions. Also corrects the TypeScript declaration for `bignumber()` and introduces a couple more common abbreviations for TypeScript types. Fixes the number-only implementations of floor, ceil, fix, and nthRoot to match the full implementation behavior on numbers, and tests this for floor. Includes some minor documentation updates and additional unit tests for the rounding functions. Reverts inclusion in AUTHORS of incorrect email for one contributor, that occurred in #2531. Resolves #2526. Resolves #2529.
1 parent c96fb1b commit 82074e8

File tree

20 files changed

+758
-451
lines changed

20 files changed

+758
-451
lines changed

AUTHORS

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,6 @@ Alfonso Valenciana <[email protected]>
179179
180180
Glen Whitney <[email protected]>
181181
Divya Yeruva <[email protected]>
182-
183182
Eternal-Rise <[email protected]>
184183
185184
NattapongSiri <[email protected]>

docs/datatypes/matrices.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,23 @@ const m1 = math.matrix([[0, 1], [0, 0]], 'sparse')
342342
const m2 = math.identity(1000, 1000, 'sparse')
343343
```
344344

345+
You can also coerce an array or matrix into sparse storage format with the
346+
`sparse` function.
347+
```js
348+
const md = math.matrix([[0, 1], [0,0]]) // dense
349+
const ms = math.sparse(md) // sparse
350+
```
351+
352+
Caution: `sparse` called on a JavaScript array of _n_ plain numbers produces
353+
a matrix with one column and _n_ rows -- in contrast to `matrix`, which
354+
produces a 1-dimensional matrix object with _n_ entries, i.e., a vector
355+
(_not_ a 1 by _n_ "row vector" nor an _n_ by 1 "column vector", but just a plain
356+
vector of length _n_).
357+
```js
358+
const mv = math.matrix([0, 0, 1]) // Has size [3]
359+
const mc = math.sparse([0, 0, 1]) // A "column vector," has size [3, 1]
360+
```
361+
345362
## API
346363

347364
All relevant functions in math.js support Matrices and Arrays. Functions like `math.add` and `math.subtract`, `math.sqrt` handle matrices element wise. There is a set of functions specifically for creating or manipulating matrices, such as:

src/factoriesNumber.js

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import {
2020
bitOrNumber,
2121
bitXorNumber,
2222
cbrtNumber,
23-
ceilNumber,
2423
combinationsNumber,
2524
coshNumber,
2625
cosNumber,
@@ -32,8 +31,6 @@ import {
3231
divideNumber,
3332
expm1Number,
3433
expNumber,
35-
fixNumber,
36-
floorNumber,
3734
gammaNumber,
3835
gcdNumber,
3936
isIntegerNumber,
@@ -52,10 +49,12 @@ import {
5249
multiplyNumber,
5350
normNumber,
5451
notNumber,
52+
nthRootNumber,
5553
orNumber,
5654
powNumber,
5755
rightArithShiftNumber,
5856
rightLogShiftNumber,
57+
roundNumber,
5958
sechNumber,
6059
secNumber,
6160
signNumber,
@@ -102,28 +101,30 @@ export const createUnaryPlus = /* #__PURE__ */ createNumberFactory('unaryPlus',
102101
export const createAbs = /* #__PURE__ */ createNumberFactory('abs', absNumber)
103102
export const createAddScalar = /* #__PURE__ */ createNumberFactory('addScalar', addNumber)
104103
export const createCbrt = /* #__PURE__ */ createNumberFactory('cbrt', cbrtNumber)
105-
export const createCeil = /* #__PURE__ */ createNumberFactory('ceil', ceilNumber)
104+
export { createCeilNumber as createCeil } from './function/arithmetic/ceil.js'
106105
export const createCube = /* #__PURE__ */ createNumberFactory('cube', cubeNumber)
107106
export const createExp = /* #__PURE__ */ createNumberFactory('exp', expNumber)
108107
export const createExpm1 = /* #__PURE__ */ createNumberFactory('expm1', expm1Number)
109-
export const createFix = /* #__PURE__ */ createNumberFactory('fix', fixNumber)
110-
export const createFloor = /* #__PURE__ */ createNumberFactory('floor', floorNumber)
108+
export { createFixNumber as createFix } from './function/arithmetic/fix.js'
109+
export { createFloorNumber as createFloor } from './function/arithmetic/floor.js'
111110
export const createGcd = /* #__PURE__ */ createNumberFactory('gcd', gcdNumber)
112111
export const createLcm = /* #__PURE__ */ createNumberFactory('lcm', lcmNumber)
113112
export const createLog10 = /* #__PURE__ */ createNumberFactory('log10', log10Number)
114113
export const createLog2 = /* #__PURE__ */ createNumberFactory('log2', log2Number)
115114
export const createMod = /* #__PURE__ */ createNumberFactory('mod', modNumber)
116115
export const createMultiplyScalar = /* #__PURE__ */ createNumberFactory('multiplyScalar', multiplyNumber)
117116
export const createMultiply = /* #__PURE__ */ createNumberFactory('multiply', multiplyNumber)
118-
export { createNthRootNumber as createNthRoot } from './function/arithmetic/nthRoot.js'
117+
export const createNthRoot = /* #__PURE__ */
118+
createNumberOptionalSecondArgFactory('nthRoot', nthRootNumber)
119119
export const createSign = /* #__PURE__ */ createNumberFactory('sign', signNumber)
120120
export const createSqrt = /* #__PURE__ */ createNumberFactory('sqrt', sqrtNumber)
121121
export const createSquare = /* #__PURE__ */ createNumberFactory('square', squareNumber)
122122
export const createSubtract = /* #__PURE__ */ createNumberFactory('subtract', subtractNumber)
123123
export const createXgcd = /* #__PURE__ */ createNumberFactory('xgcd', xgcdNumber)
124124
export const createDivideScalar = /* #__PURE__ */ createNumberFactory('divideScalar', divideNumber)
125125
export const createPow = /* #__PURE__ */ createNumberFactory('pow', powNumber)
126-
export { createRoundNumber as createRound } from './function/arithmetic/round.js'
126+
export const createRound = /* #__PURE__ */
127+
createNumberOptionalSecondArgFactory('round', roundNumber)
127128
export const createLog = /* #__PURE__ */
128129
createNumberOptionalSecondArgFactory('log', logNumber)
129130
export const createLog1p = /* #__PURE__ */ createNumberFactory('log1p', log1pNumber)

src/function/arithmetic/ceil.js

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,44 @@ import { factory } from '../../utils/factory.js'
33
import { deepMap } from '../../utils/collection.js'
44
import { nearlyEqual } from '../../utils/number.js'
55
import { nearlyEqual as bigNearlyEqual } from '../../utils/bignumber/nearlyEqual.js'
6-
import { ceilNumber } from '../../plain/number/index.js'
76
import { createAlgorithm11 } from '../../type/matrix/utils/algorithm11.js'
7+
import { createAlgorithm12 } from '../../type/matrix/utils/algorithm12.js'
88
import { createAlgorithm14 } from '../../type/matrix/utils/algorithm14.js'
99

1010
const name = 'ceil'
11-
const dependencies = ['typed', 'config', 'round', 'matrix', 'equalScalar']
11+
const dependencies = ['typed', 'config', 'round', 'matrix', 'equalScalar', 'zeros', 'DenseMatrix']
1212

13-
export const createCeil = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, round, matrix, equalScalar }) => {
13+
export const createCeilNumber = /* #__PURE__ */ factory(
14+
name, ['typed', 'config', 'round'], ({ typed, config, round }) => {
15+
return typed(name, {
16+
number: function (x) {
17+
if (nearlyEqual(x, round(x), config.epsilon)) {
18+
return round(x)
19+
} else {
20+
return Math.ceil(x)
21+
}
22+
},
23+
24+
'number, number': function (x, n) {
25+
if (nearlyEqual(x, round(x, n), config.epsilon)) {
26+
return round(x, n)
27+
} else {
28+
let [number, exponent] = `${x}e`.split('e')
29+
const result = Math.ceil(Number(`${number}e${Number(exponent) + n}`));
30+
[number, exponent] = `${result}e`.split('e')
31+
return Number(`${number}e${Number(exponent) - n}`)
32+
}
33+
}
34+
})
35+
}
36+
)
37+
38+
export const createCeil = /* #__PURE__ */ factory(name, dependencies, ({ typed, config, round, matrix, equalScalar, zeros, DenseMatrix }) => {
1439
const algorithm11 = createAlgorithm11({ typed, equalScalar })
40+
const algorithm12 = createAlgorithm12({ typed, DenseMatrix })
1541
const algorithm14 = createAlgorithm14({ typed })
1642

43+
const ceilNumber = createCeilNumber({ typed, config, round })
1744
/**
1845
* Round a value towards plus infinity
1946
* If `x` is complex, both real and imaginary part are rounded towards plus infinity.
@@ -52,24 +79,8 @@ export const createCeil = /* #__PURE__ */ factory(name, dependencies, ({ typed,
5279
* @return {number | BigNumber | Fraction | Complex | Array | Matrix} Rounded value
5380
*/
5481
return typed('ceil', {
55-
number: function (x) {
56-
if (nearlyEqual(x, round(x), config.epsilon)) {
57-
return round(x)
58-
} else {
59-
return ceilNumber(x)
60-
}
61-
},
62-
63-
'number, number': function (x, n) {
64-
if (nearlyEqual(x, round(x, n), config.epsilon)) {
65-
return round(x, n)
66-
} else {
67-
let [number, exponent] = `${x}e`.split('e')
68-
const result = Math.ceil(Number(`${number}e${Number(exponent) + n}`));
69-
[number, exponent] = `${result}e`.split('e')
70-
return Number(`${number}e${Number(exponent) - n}`)
71-
}
72-
},
82+
number: ceilNumber.signatures.number,
83+
'number,number': ceilNumber.signatures['number,number'],
7384

7485
Complex: function (x) {
7586
return x.ceil()
@@ -79,6 +90,10 @@ export const createCeil = /* #__PURE__ */ factory(name, dependencies, ({ typed,
7990
return x.ceil(n)
8091
},
8192

93+
'Complex, BigNumber': function (x, n) {
94+
return x.ceil(n.toNumber())
95+
},
96+
8297
BigNumber: function (x) {
8398
if (bigNearlyEqual(x, round(x), config.epsilon)) {
8499
return round(x)
@@ -103,12 +118,16 @@ export const createCeil = /* #__PURE__ */ factory(name, dependencies, ({ typed,
103118
return x.ceil(n)
104119
},
105120

121+
'Fraction, BigNumber': function (x, n) {
122+
return x.ceil(n.toNumber())
123+
},
124+
106125
'Array | Matrix': function (x) {
107126
// deep map collection, skip zeros since ceil(0) = 0
108127
return deepMap(x, this, true)
109128
},
110129

111-
'Array | Matrix, number': function (x, n) {
130+
'Array, number | BigNumber': function (x, n) {
112131
// deep map collection, skip zeros since ceil(0) = 0
113132
return deepMap(x, i => this(i, n), true)
114133
},
@@ -121,9 +140,17 @@ export const createCeil = /* #__PURE__ */ factory(name, dependencies, ({ typed,
121140
return algorithm14(x, y, this, false)
122141
},
123142

124-
'number | Complex | BigNumber, Array': function (x, y) {
143+
'number | Complex | Fraction | BigNumber, Array': function (x, y) {
125144
// use matrix implementation
126145
return algorithm14(matrix(y), x, this, true).valueOf()
146+
},
147+
148+
'number | Complex | Fraction | BigNumber, Matrix': function (x, y) {
149+
if (equalScalar(x, 0)) return zeros(y.size(), y.storage())
150+
if (y.storage() === 'dense') {
151+
return algorithm14(y, x, this, true)
152+
}
153+
return algorithm12(y, x, this, true)
127154
}
128155
})
129156
})

src/function/arithmetic/fix.js

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,38 @@
11
import { factory } from '../../utils/factory.js'
22
import { deepMap } from '../../utils/collection.js'
3+
import { createAlgorithm12 } from '../../type/matrix/utils/algorithm12.js'
34
import { createAlgorithm14 } from '../../type/matrix/utils/algorithm14.js'
45

56
const name = 'fix'
6-
const dependencies = ['typed', 'Complex', 'matrix', 'ceil', 'floor']
7+
const dependencies = ['typed', 'Complex', 'matrix', 'ceil', 'floor', 'equalScalar', 'zeros', 'DenseMatrix']
78

8-
export const createFix = /* #__PURE__ */ factory(name, dependencies, ({ typed, Complex, matrix, ceil, floor }) => {
9+
export const createFixNumber = /* #__PURE__ */ factory(
10+
name, ['typed', 'ceil', 'floor'], ({ typed, ceil, floor }) => {
11+
return typed(name, {
12+
number: function (x) {
13+
return (x > 0) ? floor(x) : ceil(x)
14+
},
15+
16+
'number, number': function (x, n) {
17+
return (x > 0) ? floor(x, n) : ceil(x, n)
18+
}
19+
})
20+
}
21+
)
22+
23+
export const createFix = /* #__PURE__ */ factory(name, dependencies, ({ typed, Complex, matrix, ceil, floor, equalScalar, zeros, DenseMatrix }) => {
24+
const algorithm12 = createAlgorithm12({ typed, DenseMatrix })
925
const algorithm14 = createAlgorithm14({ typed })
26+
27+
const fixNumber = createFixNumber({ typed, ceil, floor })
1028
/**
1129
* Round a value towards zero.
1230
* For matrices, the function is evaluated element wise.
1331
*
1432
* Syntax:
1533
*
1634
* math.fix(x)
35+
* math.fix(x,n)
1736
*
1837
* Examples:
1938
*
@@ -43,13 +62,8 @@ export const createFix = /* #__PURE__ */ factory(name, dependencies, ({ typed, C
4362
* @return {number | BigNumber | Fraction | Complex | Array | Matrix} Rounded value
4463
*/
4564
return typed('fix', {
46-
number: function (x) {
47-
return (x > 0) ? floor(x) : ceil(x)
48-
},
49-
50-
'number, number | BigNumber': function (x, n) {
51-
return (x > 0) ? floor(x, n) : ceil(x, n)
52-
},
65+
number: fixNumber.signatures.number,
66+
'number, number | BigNumber': fixNumber.signatures['number,number'],
5367

5468
Complex: function (x) {
5569
return new Complex(
@@ -58,7 +72,15 @@ export const createFix = /* #__PURE__ */ factory(name, dependencies, ({ typed, C
5872
)
5973
},
6074

61-
'Complex, number | BigNumber': function (x, n) {
75+
'Complex, number': function (x, n) {
76+
return new Complex(
77+
(x.re > 0) ? floor(x.re, n) : ceil(x.re, n),
78+
(x.im > 0) ? floor(x.im, n) : ceil(x.im, n)
79+
)
80+
},
81+
82+
'Complex, BigNumber': function (x, bn) {
83+
const n = bn.toNumber()
6284
return new Complex(
6385
(x.re > 0) ? floor(x.re, n) : ceil(x.re, n),
6486
(x.im > 0) ? floor(x.im, n) : ceil(x.im, n)
@@ -78,7 +100,7 @@ export const createFix = /* #__PURE__ */ factory(name, dependencies, ({ typed, C
78100
},
79101

80102
'Fraction, number | BigNumber': function (x, n) {
81-
return x.s < 0 ? x.ceil(n) : x.floor(n)
103+
return x.s < 0 ? ceil(x, n) : floor(x, n)
82104
},
83105

84106
'Array | Matrix': function (x) {
@@ -91,9 +113,17 @@ export const createFix = /* #__PURE__ */ factory(name, dependencies, ({ typed, C
91113
return deepMap(x, i => this(i, n), true)
92114
},
93115

94-
'number | Complex | BigNumber, Array': function (x, y) {
116+
'number | Complex | Fraction | BigNumber, Array': function (x, y) {
95117
// use matrix implementation
96118
return algorithm14(matrix(y), x, this, true).valueOf()
119+
},
120+
121+
'number | Complex | Fraction | BigNumber, Matrix': function (x, y) {
122+
if (equalScalar(x, 0)) return zeros(y.size(), y.storage())
123+
if (y.storage() === 'dense') {
124+
return algorithm14(y, x, this, true)
125+
}
126+
return algorithm12(y, x, this, true)
97127
}
98128
})
99129
})

0 commit comments

Comments
 (0)