smath 1.12.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +33 -27
- package/dist/index.js +550 -541
- package/package.json +3 -3
- package/types/index.d.ts +357 -351
package/dist/index.js
CHANGED
|
@@ -11,584 +11,593 @@ var __assign = (this && this.__assign) || function () {
|
|
|
11
11
|
return __assign.apply(this, arguments);
|
|
12
12
|
};
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.
|
|
14
|
+
exports.approx = approx;
|
|
15
|
+
exports.clamp = clamp;
|
|
16
|
+
exports.normalize = normalize;
|
|
17
|
+
exports.expand = expand;
|
|
18
|
+
exports.translate = translate;
|
|
19
|
+
exports.linspace = linspace;
|
|
20
|
+
exports.logspace = logspace;
|
|
21
|
+
exports.factorial = factorial;
|
|
22
|
+
exports.factors = factors;
|
|
23
|
+
exports.round2 = round2;
|
|
24
|
+
exports.error = error;
|
|
25
|
+
exports.sum = sum;
|
|
26
|
+
exports.prod = prod;
|
|
27
|
+
exports.avg = avg;
|
|
28
|
+
exports.median = median;
|
|
29
|
+
exports.varp = varp;
|
|
30
|
+
exports.vars = vars;
|
|
31
|
+
exports.stdevp = stdevp;
|
|
32
|
+
exports.stdevs = stdevs;
|
|
33
|
+
exports.runif = runif;
|
|
34
|
+
exports.rint = rint;
|
|
35
|
+
exports.rnorm = rnorm;
|
|
36
|
+
exports.rdist = rdist;
|
|
37
|
+
exports.shuffle = shuffle;
|
|
38
|
+
exports.lim = lim;
|
|
39
|
+
exports.differentiate = differentiate;
|
|
40
|
+
exports.integrate = integrate;
|
|
41
|
+
exports.rat = rat;
|
|
42
|
+
exports.mixed = mixed;
|
|
43
|
+
exports.toHex = toHex;
|
|
15
44
|
/**
|
|
16
45
|
* @packageDocumentation
|
|
17
46
|
* Small math function library
|
|
18
47
|
*
|
|
19
48
|
* 
|
|
49
|
+
* 
|
|
20
50
|
*/
|
|
21
51
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
52
|
+
* Check if two numbers are approximately equal with a maximum abolute error.
|
|
53
|
+
* @param a Any number
|
|
54
|
+
* @param b Any number
|
|
55
|
+
* @param epsilon Maximum absolute error
|
|
56
|
+
* @returns True if `a` is approximately `b`
|
|
57
|
+
* @example
|
|
58
|
+
* ```js
|
|
59
|
+
* const b1 = SMath.approx(1 / 3, 0.33, 1e-6), // false
|
|
60
|
+
* b2 = SMath.approx(1 / 3, 0.33, 1e-2); // true
|
|
61
|
+
* ```
|
|
24
62
|
*/
|
|
25
|
-
|
|
26
|
-
(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
63
|
+
function approx(a, b, epsilon) {
|
|
64
|
+
if (epsilon === void 0) { epsilon = 1e-6; }
|
|
65
|
+
return a - b < epsilon && b - a < epsilon;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Clamp a number within a range.
|
|
69
|
+
* @param n The number to clamp
|
|
70
|
+
* @param min The minimum value of the range
|
|
71
|
+
* @param max The maximum value of the range
|
|
72
|
+
* @returns A clamped number
|
|
73
|
+
* @example
|
|
74
|
+
* ```js
|
|
75
|
+
* const n1 = SMath.clamp(5, 0, 10), // 5
|
|
76
|
+
* n2 = SMath.clamp(-2, 0, 10); // 0
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
function clamp(n, min, max) {
|
|
80
|
+
if (n < min) {
|
|
81
|
+
return min;
|
|
42
82
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
* Clamp a number within a range.
|
|
46
|
-
* @param n The number to clamp
|
|
47
|
-
* @param min The minimum value of the range
|
|
48
|
-
* @param max The maximum value of the range
|
|
49
|
-
* @returns A clamped number
|
|
50
|
-
* @example
|
|
51
|
-
* ```js
|
|
52
|
-
* const n1 = SMath.clamp(5, 0, 10), // 5
|
|
53
|
-
* n2 = SMath.clamp(-2, 0, 10); // 0
|
|
54
|
-
* ```
|
|
55
|
-
*/
|
|
56
|
-
function clamp(n, min, max) {
|
|
57
|
-
if (n < min) {
|
|
58
|
-
return min;
|
|
59
|
-
}
|
|
60
|
-
if (n > max) {
|
|
61
|
-
return max;
|
|
62
|
-
}
|
|
63
|
-
return n;
|
|
83
|
+
if (n > max) {
|
|
84
|
+
return max;
|
|
64
85
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
86
|
+
return n;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Normalize the number `n` from the range `min, max` to the range `0, 1`
|
|
90
|
+
* @param n The number to normalize
|
|
91
|
+
* @param min The minimum value in the range
|
|
92
|
+
* @param max The maximum value in the range
|
|
93
|
+
* @returns A normalized value
|
|
94
|
+
* @example
|
|
95
|
+
* ```js
|
|
96
|
+
* const y = SMath.normalize(18, 9, 99); // 0.1
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
function normalize(n, min, max) {
|
|
100
|
+
if (min === max) {
|
|
101
|
+
return 0;
|
|
102
|
+
}
|
|
103
|
+
return (n - min) / (max - min);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Expand a normalized number `n` to the range `min, max`
|
|
107
|
+
* @param n A normalized number
|
|
108
|
+
* @param min The minimum value in the range
|
|
109
|
+
* @param max The maximum value in the range
|
|
110
|
+
* @returns A value within the number range
|
|
111
|
+
* @example
|
|
112
|
+
* ```js
|
|
113
|
+
* const y = SMath.expand(0.25, 4, 6); // 4.5
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
function expand(n, min, max) {
|
|
117
|
+
return (max - min) * n + min;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Translate a number `n` from the range `min1, max1` to the range `min2, max2`
|
|
121
|
+
* @param n The number to translate
|
|
122
|
+
* @param min1 The minimum value from the initial range
|
|
123
|
+
* @param max1 The maximum value from the initial range
|
|
124
|
+
* @param min2 The minimum value for the final range
|
|
125
|
+
* @param max2 The maximum value for the final range
|
|
126
|
+
* @returns A translated number in the final range
|
|
127
|
+
* @example
|
|
128
|
+
* ```js
|
|
129
|
+
* const C = 20,
|
|
130
|
+
* F = SMath.translate(C, 0, 100, 32, 212); // 68
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
function translate(n, min1, max1, min2, max2) {
|
|
134
|
+
return expand(normalize(n, min1, max1), min2, max2);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Generate an array of linearly spaced numbers.
|
|
138
|
+
* @param min The initial value of the linear space
|
|
139
|
+
* @param max The final value of the linear space
|
|
140
|
+
* @param count The number of values in the space
|
|
141
|
+
* @returns The linear space as an array of numbers
|
|
142
|
+
* @example
|
|
143
|
+
* ```js
|
|
144
|
+
* const space = SMath.linspace(1, 5, 6);
|
|
145
|
+
* // [ 1, 1.8, 2.6, 3.4, 4.2, 5 ]
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
function linspace(min, max, count) {
|
|
149
|
+
var space = [];
|
|
150
|
+
for (var i = 0; i < count; i++) {
|
|
151
|
+
space[i] = translate(i, 0, count - 1, min, max);
|
|
82
152
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
153
|
+
return space;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Generate an array of logarithmically spaced numbers.
|
|
157
|
+
* @param min The initial magnitude of the space
|
|
158
|
+
* @param max The final magnitude of the space
|
|
159
|
+
* @param count The number of values in the space
|
|
160
|
+
* @returns The logarithmic space as an array of numbers
|
|
161
|
+
* @example
|
|
162
|
+
* ```js
|
|
163
|
+
* const space = SMath.logspace(0, 2, 5);
|
|
164
|
+
* // [ 1, 3.2, 10, 31.6, 100 ]
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
function logspace(min, max, count) {
|
|
168
|
+
return linspace(min, max, count).map(function (n) { return Math.pow(10, n); });
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Compute the factorial of `n`.
|
|
172
|
+
* @param n Any positive integer
|
|
173
|
+
* @returns `n!`
|
|
174
|
+
* @example
|
|
175
|
+
* ```js
|
|
176
|
+
* const y = SMath.factorial(5); // 120
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
function factorial(n) {
|
|
180
|
+
if (n < 0 || (n | 0) !== n) {
|
|
181
|
+
throw new Error('Input must be a positive integer.');
|
|
97
182
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
* Translate a number `n` from the range `min1, max1` to the range `min2, max2`
|
|
101
|
-
* @param n The number to translate
|
|
102
|
-
* @param min1 The minimum value from the initial range
|
|
103
|
-
* @param max1 The maximum value from the initial range
|
|
104
|
-
* @param min2 The minimum value for the final range
|
|
105
|
-
* @param max2 The maximum value for the final range
|
|
106
|
-
* @returns A translated number in the final range
|
|
107
|
-
* @example
|
|
108
|
-
* ```js
|
|
109
|
-
* const C = 20,
|
|
110
|
-
* F = SMath.translate(C, 0, 100, 32, 212); // 68
|
|
111
|
-
* ```
|
|
112
|
-
*/
|
|
113
|
-
function translate(n, min1, max1, min2, max2) {
|
|
114
|
-
return expand(normalize(n, min1, max1), min2, max2);
|
|
183
|
+
else if (n === 0) {
|
|
184
|
+
return 1;
|
|
115
185
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
* Generate an array of linearly spaced numbers.
|
|
119
|
-
* @param min The initial value of the linear space
|
|
120
|
-
* @param max The final value of the linear space
|
|
121
|
-
* @param count The number of values in the space
|
|
122
|
-
* @returns The linear space as an array of numbers
|
|
123
|
-
* @example
|
|
124
|
-
* ```js
|
|
125
|
-
* const space = SMath.linspace(1, 5, 6);
|
|
126
|
-
* // [ 1, 1.8, 2.6, 3.4, 4.2, 5 ]
|
|
127
|
-
* ```
|
|
128
|
-
*/
|
|
129
|
-
function linspace(min, max, count) {
|
|
130
|
-
var space = [];
|
|
131
|
-
for (var i = 0; i < count; i++) {
|
|
132
|
-
space[i] = translate(i, 0, count - 1, min, max);
|
|
133
|
-
}
|
|
134
|
-
return space;
|
|
186
|
+
else if (n <= 2) {
|
|
187
|
+
return n;
|
|
135
188
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
* Generate an array of logarithmically spaced numbers.
|
|
139
|
-
* @param min The initial magnitude of the space
|
|
140
|
-
* @param max The final magnitude of the space
|
|
141
|
-
* @param count The number of values in the space
|
|
142
|
-
* @returns The logarithmic space as an array of numbers
|
|
143
|
-
* @example
|
|
144
|
-
* ```js
|
|
145
|
-
* const space = SMath.logspace(0, 2, 5);
|
|
146
|
-
* // [ 1, 3.2, 10, 31.6, 100 ]
|
|
147
|
-
* ```
|
|
148
|
-
*/
|
|
149
|
-
function logspace(min, max, count) {
|
|
150
|
-
return linspace(min, max, count).map(function (n) { return Math.pow(10, n); });
|
|
189
|
+
else {
|
|
190
|
+
return n * factorial(n - 1);
|
|
151
191
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Factorize `n` into its prime factors.
|
|
195
|
+
* @param n Any positive integer
|
|
196
|
+
* @returns The array of prime factors
|
|
197
|
+
* @example
|
|
198
|
+
* ```js
|
|
199
|
+
* const y = SMath.factors(12); // [ 2, 2, 3 ]
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
function factors(n) {
|
|
203
|
+
if (n < 0 || (n | 0) !== n) {
|
|
204
|
+
throw new Error('Input must be a positive integer!');
|
|
205
|
+
}
|
|
206
|
+
if (n <= 3) {
|
|
207
|
+
return [n];
|
|
208
|
+
}
|
|
209
|
+
var f = [];
|
|
210
|
+
var i = 2;
|
|
211
|
+
while (n > 1 && i <= n) {
|
|
212
|
+
if ((n / i) === ((n / i) | 0)) {
|
|
213
|
+
n /= i;
|
|
214
|
+
f.push(i);
|
|
171
215
|
}
|
|
172
216
|
else {
|
|
173
|
-
|
|
217
|
+
i++;
|
|
174
218
|
}
|
|
175
219
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
220
|
+
return f;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Round a number to the nearest multiple of an arbitrary
|
|
224
|
+
* base. Does not round when the base is set to zero.
|
|
225
|
+
* @param n Any number to round
|
|
226
|
+
* @param base Any base to round to
|
|
227
|
+
* @returns `n` rounded to the nearest multiple of `base`
|
|
228
|
+
* @example
|
|
229
|
+
* ```js
|
|
230
|
+
* const y = SMath.round2(Math.PI, 0.2); // 3.2
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
function round2(n, base) {
|
|
234
|
+
return base ? base * Math.round(n / base) : n;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Calculate the relative normalized error or deviation from any
|
|
238
|
+
* value to an accepted value. An error of 0 indicates that the
|
|
239
|
+
* two values are identical. An error of -0.1 indicates that the
|
|
240
|
+
* experimental value is 10% smaller than (90% of) the accepted
|
|
241
|
+
* value. An error of 1.0 indicates that the experimental value
|
|
242
|
+
* is 100% greater (or twice the size) of the accepted value.
|
|
243
|
+
* @param experimental The value observed or produced by a test
|
|
244
|
+
* @param actual The accepted or theoretical value
|
|
245
|
+
* @returns The relative (normalized) error
|
|
246
|
+
* @example
|
|
247
|
+
* ```js
|
|
248
|
+
* const e = SMath.error(22.5, 25); // -0.1
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
251
|
+
function error(experimental, actual) {
|
|
252
|
+
return (experimental - actual) / actual;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Add up all the inputs.
|
|
256
|
+
* If none are present, returns 0.
|
|
257
|
+
* @param data An array of numeric inputs
|
|
258
|
+
* @returns The sum total
|
|
259
|
+
* @example
|
|
260
|
+
* ```js
|
|
261
|
+
* const y = SMath.sum([1, 2, 3]); // 6
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
function sum(data) {
|
|
265
|
+
return data.reduce(function (a, b) { return a + b; }, 0);
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Multiply all the inputs.
|
|
269
|
+
* If none are present, returns 1.
|
|
270
|
+
* @param data An array of numeric inputs
|
|
271
|
+
* @returns The product
|
|
272
|
+
* @example
|
|
273
|
+
* ```js
|
|
274
|
+
* const y = SMath.prod([2, 2, 3, 5]); // 60
|
|
275
|
+
* ```
|
|
276
|
+
*/
|
|
277
|
+
function prod(data) {
|
|
278
|
+
return data.reduce(function (a, b) { return a * b; }, 1);
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Compute the average, or mean, of a set of numbers.
|
|
282
|
+
* @param data An array of numeric inputs
|
|
283
|
+
* @returns The average, or mean
|
|
284
|
+
* @example
|
|
285
|
+
* ```js
|
|
286
|
+
* const y = SMath.avg([1, 2, 4, 4]); // 2.75
|
|
287
|
+
* ```
|
|
288
|
+
*/
|
|
289
|
+
function avg(data) {
|
|
290
|
+
return sum(data) / data.length;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Compute the median of a set of numbers.
|
|
294
|
+
* @param data An array of numeric inputs
|
|
295
|
+
* @returns The median of the dataset
|
|
296
|
+
* @example
|
|
297
|
+
* ```js
|
|
298
|
+
* const y = SMath.median([2, 5, 3, 1]); // 2.5
|
|
299
|
+
* ```
|
|
300
|
+
*/
|
|
301
|
+
function median(data) {
|
|
302
|
+
data.sort(function (a, b) { return a - b; });
|
|
303
|
+
if (data.length % 2) {
|
|
304
|
+
return data[(data.length - 1) / 2];
|
|
205
305
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
function
|
|
219
|
-
|
|
306
|
+
return avg([data[data.length / 2 - 1], data[data.length / 2]]);
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Compute the variance of a **complete population**.
|
|
310
|
+
* @param data An array of numeric inputs
|
|
311
|
+
* @returns The population variance
|
|
312
|
+
* @example
|
|
313
|
+
* ```js
|
|
314
|
+
* const y = SMath.varp([1, 2, 4, 4]); // 1.6875
|
|
315
|
+
* ```
|
|
316
|
+
*/
|
|
317
|
+
function varp(data) {
|
|
318
|
+
var mean = avg(data), squares = data.map(function (x) { return Math.pow((x - mean), 2); });
|
|
319
|
+
return sum(squares) / data.length;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Compute the variance of a **sample**.
|
|
323
|
+
* @param data An array of numeric inputs
|
|
324
|
+
* @returns The sample variance
|
|
325
|
+
* @example
|
|
326
|
+
* ```js
|
|
327
|
+
* const y = SMath.vars([1, 2, 4, 4]); // 2.25
|
|
328
|
+
* ```
|
|
329
|
+
*/
|
|
330
|
+
function vars(data) {
|
|
331
|
+
var mean = avg(data), squares = data.map(function (x) { return Math.pow((x - mean), 2); });
|
|
332
|
+
return sum(squares) / (data.length - 1);
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Compute the standard deviation of a **complete population**.
|
|
336
|
+
* @param data An array of numeric inputs
|
|
337
|
+
* @returns The population standard deviation
|
|
338
|
+
* @example
|
|
339
|
+
* ```js
|
|
340
|
+
* const y = SMath.stdevp([1, 2, 3, 4]); // 1.118...
|
|
341
|
+
* ```
|
|
342
|
+
*/
|
|
343
|
+
function stdevp(data) {
|
|
344
|
+
return Math.sqrt(varp(data));
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Compute the standard deviation of a **sample**.
|
|
348
|
+
* @param data An array of numeric inputs
|
|
349
|
+
* @returns The sample standard deviation
|
|
350
|
+
* @example
|
|
351
|
+
* ```js
|
|
352
|
+
* const y = SMath.stdevs([1, 2, 3, 4]); // 1.29...
|
|
353
|
+
* ```
|
|
354
|
+
*/
|
|
355
|
+
function stdevs(data) {
|
|
356
|
+
return Math.sqrt(vars(data));
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Generate a uniformly-distributed floating-point number within the range.
|
|
360
|
+
* @param min The minimum bound
|
|
361
|
+
* @param max The maximum bound
|
|
362
|
+
* @returns A random float within the range
|
|
363
|
+
* @example
|
|
364
|
+
* ```js
|
|
365
|
+
* const y = SMath.runif(-2, 2); // 0.376...
|
|
366
|
+
* ```
|
|
367
|
+
*/
|
|
368
|
+
function runif(min, max) {
|
|
369
|
+
return expand(Math.random(), min, max);
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Generate a uniformly-distributed integer within the range.
|
|
373
|
+
* @param min The minimum bound (inclusive)
|
|
374
|
+
* @param max The maximum bound (inclusive)
|
|
375
|
+
* @returns A random integer within the range
|
|
376
|
+
* @example
|
|
377
|
+
* ```js
|
|
378
|
+
* const y = SMath.rint(-4, 3); // -4
|
|
379
|
+
* ```
|
|
380
|
+
*/
|
|
381
|
+
function rint(min, max) {
|
|
382
|
+
min |= 0;
|
|
383
|
+
max |= 0;
|
|
384
|
+
if (min < 0) {
|
|
385
|
+
min--;
|
|
220
386
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
* Calculate the relative normalized error or deviation from any
|
|
224
|
-
* value to an accepted value. An error of 0 indicates that the
|
|
225
|
-
* two values are identical. An error of -0.1 indicates that the
|
|
226
|
-
* experimental value is 10% smaller than (90% of) the accepted
|
|
227
|
-
* value. An error of 1.0 indicates that the experimental value
|
|
228
|
-
* is 100% greater (or twice the size) of the accepted value.
|
|
229
|
-
* @param experimental The value observed or produced by a test
|
|
230
|
-
* @param actual The accepted or theoretical value
|
|
231
|
-
* @returns The relative (normalized) error
|
|
232
|
-
* @example
|
|
233
|
-
* ```js
|
|
234
|
-
* const e = SMath.error(22.5, 25); // -0.1
|
|
235
|
-
* ```
|
|
236
|
-
*/
|
|
237
|
-
function error(experimental, actual) {
|
|
238
|
-
return (experimental - actual) / actual;
|
|
387
|
+
if (max > 0) {
|
|
388
|
+
max++;
|
|
239
389
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
390
|
+
return clamp(runif(min, max), min, max) | 0; // `| 0` pulls toward 0
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Generate a normally-distributed floating-point number.
|
|
394
|
+
* @param mean The mean of the population distribution
|
|
395
|
+
* @param stdev The standard deviation of the population
|
|
396
|
+
* @returns A random float
|
|
397
|
+
* @example
|
|
398
|
+
* ```js
|
|
399
|
+
* const y = SMath.rnorm(2, 3); // 1.627...
|
|
400
|
+
* ```
|
|
401
|
+
*/
|
|
402
|
+
function rnorm(mean, stdev) {
|
|
403
|
+
if (mean === void 0) { mean = 0; }
|
|
404
|
+
if (stdev === void 0) { stdev = 1; }
|
|
405
|
+
return mean + stdev * Math.sqrt(-2 * Math.log(Math.random())) * Math.cos(2 * Math.PI * Math.random());
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Generate a population of normally-distributed floating-point numbers.
|
|
409
|
+
* @param count The number of values to generate
|
|
410
|
+
* @param mean The mean of the population distribution
|
|
411
|
+
* @param stdev The standard deviation of the population
|
|
412
|
+
* @returns A population of random floats
|
|
413
|
+
* @example
|
|
414
|
+
* ```js
|
|
415
|
+
* const dataset = SMath.rdist(3); // [ 1.051..., -0.779..., -2.254... ]
|
|
416
|
+
* ```
|
|
417
|
+
*/
|
|
418
|
+
function rdist(count, mean, stdev) {
|
|
419
|
+
if (mean === void 0) { mean = 0; }
|
|
420
|
+
if (stdev === void 0) { stdev = 1; }
|
|
421
|
+
var distribution = [];
|
|
422
|
+
for (var i = 0; i < count; i++) {
|
|
423
|
+
distribution[i] = rnorm(mean, stdev);
|
|
253
424
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
425
|
+
return distribution;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Randomize an array of arbitrary elements.
|
|
429
|
+
* @param stack An array of arbitrary elements
|
|
430
|
+
* @returns The `stack` array in a random order
|
|
431
|
+
* @example
|
|
432
|
+
* ```js
|
|
433
|
+
* const shuffled = SMath.shuffle(['a', 'b', 'c']); // [ 'c', 'a', 'b' ]
|
|
434
|
+
* ```
|
|
435
|
+
*/
|
|
436
|
+
function shuffle(stack) {
|
|
437
|
+
var rawData = [];
|
|
438
|
+
for (var _i = 0, stack_1 = stack; _i < stack_1.length; _i++) {
|
|
439
|
+
var item = stack_1[_i];
|
|
440
|
+
rawData.push({ index: Math.random(), value: item });
|
|
267
441
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
442
|
+
return rawData.sort(function (a, b) { return a.index - b.index; }).map(function (a) { return a.value; });
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Take the limit of a function. A return value of `NaN` indicates
|
|
446
|
+
* that no limit exists either due to a discontinuity or imaginary value.
|
|
447
|
+
* @param f Function `f(x)`
|
|
448
|
+
* @param x The x-value where to take the limit
|
|
449
|
+
* @param h The approach distance
|
|
450
|
+
* @param discontinuity_cutoff The discontinuity cutoff
|
|
451
|
+
* @returns `lim(f(x->x))`
|
|
452
|
+
* @example
|
|
453
|
+
* ```js
|
|
454
|
+
* const y = SMath.lim(Math.log, 0); // -Infinity
|
|
455
|
+
* ```
|
|
456
|
+
*/
|
|
457
|
+
function lim(f, x, h, discontinuity_cutoff) {
|
|
458
|
+
if (h === void 0) { h = 1e-3; }
|
|
459
|
+
if (discontinuity_cutoff === void 0) { discontinuity_cutoff = 1; }
|
|
460
|
+
var center = f(x), left1 = f(x - h), left2 = f(x - h / 2), right1 = f(x + h), right2 = f(x + h / 2);
|
|
461
|
+
var left, right;
|
|
462
|
+
if (Number.isFinite(center)) {
|
|
463
|
+
return center;
|
|
280
464
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
* @returns The median of the dataset
|
|
286
|
-
* @example
|
|
287
|
-
* ```js
|
|
288
|
-
* const y = SMath.median([2, 5, 3, 1]); // 2.5
|
|
289
|
-
* ```
|
|
290
|
-
*/
|
|
291
|
-
function median(data) {
|
|
292
|
-
data.sort(function (a, b) { return a - b; });
|
|
293
|
-
if (data.length % 2) {
|
|
294
|
-
return data[(data.length - 1) / 2];
|
|
465
|
+
// Check the limit approaching from the left
|
|
466
|
+
if (Number.isFinite(left1) && Number.isFinite(left2)) {
|
|
467
|
+
if (left2 > left1 + 2 * h) {
|
|
468
|
+
left = Infinity;
|
|
295
469
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
SMath.median = median;
|
|
299
|
-
/**
|
|
300
|
-
* Compute the variance of a **complete population**.
|
|
301
|
-
* @param data An array of numeric inputs
|
|
302
|
-
* @returns The population variance
|
|
303
|
-
* @example
|
|
304
|
-
* ```js
|
|
305
|
-
* const y = SMath.varp([1, 2, 4, 4]); // 1.6875
|
|
306
|
-
* ```
|
|
307
|
-
*/
|
|
308
|
-
function varp(data) {
|
|
309
|
-
var mean = avg(data), squares = data.map(function (x) { return Math.pow((x - mean), 2); });
|
|
310
|
-
return sum(squares) / data.length;
|
|
311
|
-
}
|
|
312
|
-
SMath.varp = varp;
|
|
313
|
-
/**
|
|
314
|
-
* Compute the variance of a **sample**.
|
|
315
|
-
* @param data An array of numeric inputs
|
|
316
|
-
* @returns The sample variance
|
|
317
|
-
* @example
|
|
318
|
-
* ```js
|
|
319
|
-
* const y = SMath.vars([1, 2, 4, 4]); // 2.25
|
|
320
|
-
* ```
|
|
321
|
-
*/
|
|
322
|
-
function vars(data) {
|
|
323
|
-
var mean = avg(data), squares = data.map(function (x) { return Math.pow((x - mean), 2); });
|
|
324
|
-
return sum(squares) / (data.length - 1);
|
|
325
|
-
}
|
|
326
|
-
SMath.vars = vars;
|
|
327
|
-
/**
|
|
328
|
-
* Compute the standard deviation of a **complete population**.
|
|
329
|
-
* @param data An array of numeric inputs
|
|
330
|
-
* @returns The population standard deviation
|
|
331
|
-
* @example
|
|
332
|
-
* ```js
|
|
333
|
-
* const y = SMath.stdevp([1, 2, 3, 4]); // 1.118...
|
|
334
|
-
* ```
|
|
335
|
-
*/
|
|
336
|
-
function stdevp(data) {
|
|
337
|
-
return Math.sqrt(varp(data));
|
|
338
|
-
}
|
|
339
|
-
SMath.stdevp = stdevp;
|
|
340
|
-
/**
|
|
341
|
-
* Compute the standard deviation of a **sample**.
|
|
342
|
-
* @param data An array of numeric inputs
|
|
343
|
-
* @returns The sample standard deviation
|
|
344
|
-
* @example
|
|
345
|
-
* ```js
|
|
346
|
-
* const y = SMath.stdevs([1, 2, 3, 4]); // 1.29...
|
|
347
|
-
* ```
|
|
348
|
-
*/
|
|
349
|
-
function stdevs(data) {
|
|
350
|
-
return Math.sqrt(vars(data));
|
|
351
|
-
}
|
|
352
|
-
SMath.stdevs = stdevs;
|
|
353
|
-
/**
|
|
354
|
-
* Generate a uniformly-distributed floating-point number within the range.
|
|
355
|
-
* @param min The minimum bound
|
|
356
|
-
* @param max The maximum bound
|
|
357
|
-
* @returns A random float within the range
|
|
358
|
-
* @example
|
|
359
|
-
* ```js
|
|
360
|
-
* const y = SMath.runif(-2, 2); // 0.376...
|
|
361
|
-
* ```
|
|
362
|
-
*/
|
|
363
|
-
function runif(min, max) {
|
|
364
|
-
return expand(Math.random(), min, max);
|
|
365
|
-
}
|
|
366
|
-
SMath.runif = runif;
|
|
367
|
-
/**
|
|
368
|
-
* Generate a uniformly-distributed integer within the range.
|
|
369
|
-
* @param min The minimum bound (inclusive)
|
|
370
|
-
* @param max The maximum bound (inclusive)
|
|
371
|
-
* @returns A random integer within the range
|
|
372
|
-
* @example
|
|
373
|
-
* ```js
|
|
374
|
-
* const y = SMath.rint(-4, 3); // -4
|
|
375
|
-
* ```
|
|
376
|
-
*/
|
|
377
|
-
function rint(min, max) {
|
|
378
|
-
min |= 0;
|
|
379
|
-
max |= 0;
|
|
380
|
-
if (min < 0) {
|
|
381
|
-
min--;
|
|
470
|
+
else if (left2 < left1 - 2 * h) {
|
|
471
|
+
left = -Infinity;
|
|
382
472
|
}
|
|
383
|
-
|
|
384
|
-
|
|
473
|
+
else {
|
|
474
|
+
left = avg([left1, left2]);
|
|
385
475
|
}
|
|
386
|
-
return clamp(runif(min, max), min, max) | 0; // `| 0` pulls toward 0
|
|
387
|
-
}
|
|
388
|
-
SMath.rint = rint;
|
|
389
|
-
/**
|
|
390
|
-
* Generate a normally-distributed floating-point number.
|
|
391
|
-
* @param mean The mean of the population distribution
|
|
392
|
-
* @param stdev The standard deviation of the population
|
|
393
|
-
* @returns A random float
|
|
394
|
-
* @example
|
|
395
|
-
* ```js
|
|
396
|
-
* const y = SMath.rnorm(2, 3); // 1.627...
|
|
397
|
-
* ```
|
|
398
|
-
*/
|
|
399
|
-
function rnorm(mean, stdev) {
|
|
400
|
-
if (mean === void 0) { mean = 0; }
|
|
401
|
-
if (stdev === void 0) { stdev = 1; }
|
|
402
|
-
return mean + stdev * Math.sqrt(-2 * Math.log(Math.random())) * Math.cos(2 * Math.PI * Math.random());
|
|
403
476
|
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
* Generate a population of normally-distributed floating-point numbers.
|
|
407
|
-
* @param count The number of values to generate
|
|
408
|
-
* @param mean The mean of the population distribution
|
|
409
|
-
* @param stdev The standard deviation of the population
|
|
410
|
-
* @returns A population of random floats
|
|
411
|
-
* @example
|
|
412
|
-
* ```js
|
|
413
|
-
* const dataset = SMath.rdist(3); // [ 1.051..., -0.779..., -2.254... ]
|
|
414
|
-
* ```
|
|
415
|
-
*/
|
|
416
|
-
function rdist(count, mean, stdev) {
|
|
417
|
-
if (mean === void 0) { mean = 0; }
|
|
418
|
-
if (stdev === void 0) { stdev = 1; }
|
|
419
|
-
var distribution = [];
|
|
420
|
-
for (var i = 0; i < count; i++) {
|
|
421
|
-
distribution[i] = rnorm(mean, stdev);
|
|
422
|
-
}
|
|
423
|
-
return distribution;
|
|
477
|
+
else if (left1 === left2) { // Handles +/-Infinity case
|
|
478
|
+
left = left1;
|
|
424
479
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
* Randomize an array of arbitrary elements.
|
|
428
|
-
* @param stack An array of arbitrary elements
|
|
429
|
-
* @returns The `stack` array in a random order
|
|
430
|
-
* @example
|
|
431
|
-
* ```js
|
|
432
|
-
* const shuffled = SMath.shuffle(['a', 'b', 'c']); // [ 'c', 'a', 'b' ]
|
|
433
|
-
* ```
|
|
434
|
-
*/
|
|
435
|
-
function shuffle(stack) {
|
|
436
|
-
var rawData = [];
|
|
437
|
-
for (var _i = 0, stack_1 = stack; _i < stack_1.length; _i++) {
|
|
438
|
-
var item = stack_1[_i];
|
|
439
|
-
rawData.push({ index: Math.random(), value: item });
|
|
440
|
-
}
|
|
441
|
-
return rawData.sort(function (a, b) { return a.index - b.index; }).map(function (a) { return a.value; });
|
|
480
|
+
else {
|
|
481
|
+
left = NaN;
|
|
442
482
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
* @param f Function `f(x)`
|
|
448
|
-
* @param x The x-value where to take the limit
|
|
449
|
-
* @param h The approach distance
|
|
450
|
-
* @param discontinuity_cutoff The discontinuity cutoff
|
|
451
|
-
* @returns `lim(f(x->x))`
|
|
452
|
-
* @example
|
|
453
|
-
* ```js
|
|
454
|
-
* const y = SMath.lim(Math.log, 0); // -Infinity
|
|
455
|
-
* ```
|
|
456
|
-
*/
|
|
457
|
-
function lim(f, x, h, discontinuity_cutoff) {
|
|
458
|
-
if (h === void 0) { h = 1e-3; }
|
|
459
|
-
if (discontinuity_cutoff === void 0) { discontinuity_cutoff = 1; }
|
|
460
|
-
var center = f(x), left1 = f(x - h), left2 = f(x - h / 2), right1 = f(x + h), right2 = f(x + h / 2);
|
|
461
|
-
var left, right;
|
|
462
|
-
if (Number.isFinite(center)) {
|
|
463
|
-
return center;
|
|
464
|
-
}
|
|
465
|
-
// Check the limit approaching from the left
|
|
466
|
-
if (Number.isFinite(left1) && Number.isFinite(left2)) {
|
|
467
|
-
if (left2 > left1 + 2 * h) {
|
|
468
|
-
left = Infinity;
|
|
469
|
-
}
|
|
470
|
-
else if (left2 < left1 - 2 * h) {
|
|
471
|
-
left = -Infinity;
|
|
472
|
-
}
|
|
473
|
-
else {
|
|
474
|
-
left = avg([left1, left2]);
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
else if (left1 === left2) { // Handles +/-Infinity case
|
|
478
|
-
left = left1;
|
|
479
|
-
}
|
|
480
|
-
else {
|
|
481
|
-
left = NaN;
|
|
483
|
+
// Check the limit approaching from the right
|
|
484
|
+
if (Number.isFinite(right1) && Number.isFinite(right2)) {
|
|
485
|
+
if (right2 > right1 + 2 * h) {
|
|
486
|
+
right = Infinity;
|
|
482
487
|
}
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
if (right2 > right1 + 2 * h) {
|
|
486
|
-
right = Infinity;
|
|
487
|
-
}
|
|
488
|
-
else if (right2 < right1 - 2 * h) {
|
|
489
|
-
right = -Infinity;
|
|
490
|
-
}
|
|
491
|
-
else {
|
|
492
|
-
right = avg([right1, right2]);
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
else if (right1 === right2) { // Handles +/-Infinity case
|
|
496
|
-
right = right1;
|
|
497
|
-
}
|
|
498
|
-
else {
|
|
499
|
-
right = NaN;
|
|
500
|
-
}
|
|
501
|
-
// Check if limits match or are close
|
|
502
|
-
if (left === right) { // Handles +/-Infinity case
|
|
503
|
-
return left;
|
|
504
|
-
}
|
|
505
|
-
else if (SMath.approx(left, right, discontinuity_cutoff)) {
|
|
506
|
-
return avg([left, right]);
|
|
507
|
-
}
|
|
508
|
-
else if (!Number.isNaN(left) && Number.isNaN(right)) {
|
|
509
|
-
return left;
|
|
510
|
-
}
|
|
511
|
-
else if (Number.isNaN(left) && !Number.isNaN(right)) {
|
|
512
|
-
return right;
|
|
488
|
+
else if (right2 < right1 - 2 * h) {
|
|
489
|
+
right = -Infinity;
|
|
513
490
|
}
|
|
514
491
|
else {
|
|
515
|
-
|
|
492
|
+
right = avg([right1, right2]);
|
|
516
493
|
}
|
|
517
494
|
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
* Take the derivative of a function.
|
|
521
|
-
* @param f Function `f(x)`
|
|
522
|
-
* @param x The x-value where to evaluate the derivative
|
|
523
|
-
* @param h Small step value
|
|
524
|
-
* @returns `f'(x)`
|
|
525
|
-
* @example
|
|
526
|
-
* ```js
|
|
527
|
-
* const y = SMath.differentiate(x => 3 * x ** 2, 2); // 12
|
|
528
|
-
* ```
|
|
529
|
-
*/
|
|
530
|
-
function differentiate(f, x, h) {
|
|
531
|
-
if (h === void 0) { h = 1e-3; }
|
|
532
|
-
return (f(x + h) - f(x - h)) / (2 * h);
|
|
495
|
+
else if (right1 === right2) { // Handles +/-Infinity case
|
|
496
|
+
right = right1;
|
|
533
497
|
}
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
* Compute the definite integral of a function.
|
|
537
|
-
* @param f Function `f(x)`
|
|
538
|
-
* @param a The miminum integral bound
|
|
539
|
-
* @param b The maximum integral bound
|
|
540
|
-
* @param Ndx The number of rectangles to compute
|
|
541
|
-
* @returns `F(b)-F(a)`
|
|
542
|
-
* @example
|
|
543
|
-
* ```js
|
|
544
|
-
* const y = SMath.integrate(x => 3 * x ** 2, 1, 2); // 7
|
|
545
|
-
* ```
|
|
546
|
-
*/
|
|
547
|
-
function integrate(f, a, b, Ndx) {
|
|
548
|
-
if (Ndx === void 0) { Ndx = 1e3; }
|
|
549
|
-
return ((b - a) / Ndx) * sum(linspace(a, b, Ndx).map(function (x) { return f(x); }));
|
|
498
|
+
else {
|
|
499
|
+
right = NaN;
|
|
550
500
|
}
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
* const frac = SMath.rat(0.625); // { num: 5, den: 8 }
|
|
561
|
-
* ```
|
|
562
|
-
*/
|
|
563
|
-
function rat(n, epsilon) {
|
|
564
|
-
if (epsilon === void 0) { epsilon = 1e-6; }
|
|
565
|
-
var num = 0, den = 1, sign = n < 0 ? -1 : 1;
|
|
566
|
-
while (!approx(sign * n, num / den, epsilon)) {
|
|
567
|
-
if (sign * n > num / den) {
|
|
568
|
-
num++;
|
|
569
|
-
}
|
|
570
|
-
else {
|
|
571
|
-
den++;
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
return { num: sign * num, den: den };
|
|
501
|
+
// Check if limits match or are close
|
|
502
|
+
if (left === right) { // Handles +/-Infinity case
|
|
503
|
+
return left;
|
|
504
|
+
}
|
|
505
|
+
else if (approx(left, right, discontinuity_cutoff)) {
|
|
506
|
+
return avg([left, right]);
|
|
507
|
+
}
|
|
508
|
+
else if (!Number.isNaN(left) && Number.isNaN(right)) {
|
|
509
|
+
return left;
|
|
575
510
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
* Convert an arbitrary decimal number into a simplified fraction, after
|
|
579
|
-
* breaking out the whole number part first. See `rat()` for keeping the
|
|
580
|
-
* number as a ratio without separating the whole number part.
|
|
581
|
-
* @param n A decimal number to convert
|
|
582
|
-
* @param epsilon Maximum absolute error
|
|
583
|
-
* @returns An object containing the whole part and fraction numerator and denominator
|
|
584
|
-
* @example
|
|
585
|
-
* ```js
|
|
586
|
-
* const frac = SMath.mixed(-8 / 6); // { whole: -1, num: 1, den: 3 }
|
|
587
|
-
* ```
|
|
588
|
-
*/
|
|
589
|
-
function mixed(n, epsilon) {
|
|
590
|
-
if (epsilon === void 0) { epsilon = 1e-6; }
|
|
591
|
-
return __assign({ whole: n | 0 }, rat(n < -1 ? (n | 0) - n : n - (n | 0), epsilon));
|
|
511
|
+
else if (Number.isNaN(left) && !Number.isNaN(right)) {
|
|
512
|
+
return right;
|
|
592
513
|
}
|
|
593
|
-
|
|
594
|
-
|
|
514
|
+
else {
|
|
515
|
+
return NaN;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Take the derivative of a function.
|
|
520
|
+
* @param f Function `f(x)`
|
|
521
|
+
* @param x The x-value where to evaluate the derivative
|
|
522
|
+
* @param h Small step value
|
|
523
|
+
* @returns `f'(x)`
|
|
524
|
+
* @example
|
|
525
|
+
* ```js
|
|
526
|
+
* const y = SMath.differentiate(x => 3 * x ** 2, 2); // 12
|
|
527
|
+
* ```
|
|
528
|
+
*/
|
|
529
|
+
function differentiate(f, x, h) {
|
|
530
|
+
if (h === void 0) { h = 1e-3; }
|
|
531
|
+
return (f(x + h) - f(x - h)) / (2 * h);
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Compute the definite integral of a function.
|
|
535
|
+
* @param f Function `f(x)`
|
|
536
|
+
* @param a The miminum integral bound
|
|
537
|
+
* @param b The maximum integral bound
|
|
538
|
+
* @param Ndx The number of rectangles to compute
|
|
539
|
+
* @returns `F(b)-F(a)`
|
|
540
|
+
* @example
|
|
541
|
+
* ```js
|
|
542
|
+
* const y = SMath.integrate(x => 3 * x ** 2, 1, 2); // 7
|
|
543
|
+
* ```
|
|
544
|
+
*/
|
|
545
|
+
function integrate(f, a, b, Ndx) {
|
|
546
|
+
if (Ndx === void 0) { Ndx = 1e3; }
|
|
547
|
+
return ((b - a) / Ndx) * sum(linspace(a, b, Ndx).map(function (x) { return f(x); }));
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Convert an arbitrary decimal number into a simplified fraction (or ratio).
|
|
551
|
+
* See `mixed()` for instructions on how to break out the whole number part.
|
|
552
|
+
* @param n The decimal number to convert
|
|
553
|
+
* @param epsilon Maximum absolute error
|
|
554
|
+
* @returns An object containing the fraction's numerator and denominator
|
|
555
|
+
* @example
|
|
556
|
+
* ```js
|
|
557
|
+
* const frac = SMath.rat(0.625); // { num: 5, den: 8 }
|
|
558
|
+
* ```
|
|
559
|
+
*/
|
|
560
|
+
function rat(n, epsilon) {
|
|
561
|
+
if (epsilon === void 0) { epsilon = 1e-6; }
|
|
562
|
+
var num = 0, den = 1;
|
|
563
|
+
var sign = n < 0 ? -1 : 1;
|
|
564
|
+
while (!approx(sign * n, num / den, epsilon)) {
|
|
565
|
+
if (sign * n > num / den) {
|
|
566
|
+
num++;
|
|
567
|
+
}
|
|
568
|
+
else {
|
|
569
|
+
den++;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
return { num: sign * num, den: den };
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* Convert an arbitrary decimal number into a simplified fraction, after
|
|
576
|
+
* breaking out the whole number part first. See `rat()` for keeping the
|
|
577
|
+
* number as a ratio without separating the whole number part.
|
|
578
|
+
* @param n A decimal number to convert
|
|
579
|
+
* @param epsilon Maximum absolute error
|
|
580
|
+
* @returns An object containing the whole part and fraction numerator and denominator
|
|
581
|
+
* @example
|
|
582
|
+
* ```js
|
|
583
|
+
* const frac = SMath.mixed(-8 / 6); // { whole: -1, num: 1, den: 3 }
|
|
584
|
+
* ```
|
|
585
|
+
*/
|
|
586
|
+
function mixed(n, epsilon) {
|
|
587
|
+
if (epsilon === void 0) { epsilon = 1e-6; }
|
|
588
|
+
return __assign({ whole: n | 0 }, rat(n < -1 ? (n | 0) - n : n - (n | 0), epsilon));
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* Convert any number to its hexadecimal equivalent.
|
|
592
|
+
* @param n A decimal number to convert
|
|
593
|
+
* @param length The minimum number of digits to show
|
|
594
|
+
* @returns The number `n` converted to hexadecimal
|
|
595
|
+
* @example
|
|
596
|
+
* ```js
|
|
597
|
+
* const hex = SMath.toHex(10, 2); // '0A'
|
|
598
|
+
* ```
|
|
599
|
+
*/
|
|
600
|
+
function toHex(n, length) {
|
|
601
|
+
if (length === void 0) { length = 0; }
|
|
602
|
+
return (n < 0 ? '-' : '') + (n < 0 ? -n : n).toString(16).padStart(length, '0').toUpperCase();
|
|
603
|
+
}
|