smath 1.12.1 → 1.13.1

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