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/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.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
18
47
  *
19
48
  * ![NPM Downloads](https://img.shields.io/npm/d18m/smath)
49
+ * ![NPM Last Update](https://img.shields.io/npm/last-update/smath)
20
50
  */
21
51
  /**
22
- * Contains a small math function library including
23
- * 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
+ * ```
24
62
  */
25
- var SMath;
26
- (function (SMath) {
27
- /**
28
- * Check if two numbers are approximately equal with a maximum abolute error.
29
- * @param a Any number
30
- * @param b Any number
31
- * @param epsilon Maximum absolute error
32
- * @returns True if `a` is approximately `b`
33
- * @example
34
- * ```js
35
- * const b1 = SMath.approx(1 / 3, 0.33, 1e-6), // false
36
- * b2 = SMath.approx(1 / 3, 0.33, 1e-2); // true
37
- * ```
38
- */
39
- function approx(a, b, epsilon) {
40
- if (epsilon === void 0) { epsilon = 1e-6; }
41
- 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;
42
82
  }
43
- SMath.approx = approx;
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
- SMath.clamp = clamp;
66
- /**
67
- * Normalize the number `n` from the range `min, max` to the range `0, 1`
68
- * @param n The number to normalize
69
- * @param min The minimum value in the range
70
- * @param max The maximum value in the range
71
- * @returns A normalized value
72
- * @example
73
- * ```js
74
- * const y = SMath.normalize(18, 9, 99); // 0.1
75
- * ```
76
- */
77
- function normalize(n, min, max) {
78
- if (min === max) {
79
- return 0;
80
- }
81
- 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;
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
- SMath.normalize = normalize;
84
- /**
85
- * Expand a normalized number `n` to the range `min, max`
86
- * @param n A normalized number
87
- * @param min The minimum value in the range
88
- * @param max The maximum value in the range
89
- * @returns A value within the number range
90
- * @example
91
- * ```js
92
- * const y = SMath.expand(0.25, 4, 6); // 4.5
93
- * ```
94
- */
95
- function expand(n, min, max) {
96
- return (max - min) * n + min;
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
- SMath.expand = expand;
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
- SMath.translate = translate;
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
- SMath.linspace = linspace;
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
- SMath.logspace = logspace;
153
- /**
154
- * Compute the factorial of `n`.
155
- * @param n Any positive integer
156
- * @returns `n!`
157
- * @example
158
- * ```js
159
- * const y = SMath.factorial(5); // 120
160
- * ```
161
- */
162
- function factorial(n) {
163
- if (n < 0 || (n | 0) !== n) {
164
- throw new Error('Input must be a positive integer.');
165
- }
166
- else if (n === 0) {
167
- return 1;
168
- }
169
- else if (n <= 2) {
170
- return n;
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
- return n * factorial(n - 1);
217
+ i++;
174
218
  }
175
219
  }
176
- SMath.factorial = factorial;
177
- /**
178
- * Factorize `n` into its prime factors.
179
- * @param n Any positive integer
180
- * @returns The array of prime factors
181
- * @example
182
- * ```js
183
- * const y = SMath.factors(12); // [ 2, 2, 3 ]
184
- * ```
185
- */
186
- function factors(n) {
187
- if (n < 0 || (n | 0) !== n) {
188
- throw new Error('Input must be a positive integer!');
189
- }
190
- if (n <= 3) {
191
- return [n];
192
- }
193
- var f = [];
194
- var i = 2;
195
- while (n > 1 && i <= n) {
196
- if ((n / i) === ((n / i) | 0)) {
197
- n /= i;
198
- f.push(i);
199
- }
200
- else {
201
- i++;
202
- }
203
- }
204
- 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];
205
305
  }
206
- SMath.factors = factors;
207
- /**
208
- * Round a number to the nearest multiple of an arbitrary
209
- * base. Does not round when the base is set to zero.
210
- * @param n Any number to round
211
- * @param base Any base to round to
212
- * @returns `n` rounded to the nearest multiple of `base`
213
- * @example
214
- * ```js
215
- * const y = SMath.round2(Math.PI, 0.2); // 3.2
216
- * ```
217
- */
218
- function round2(n, base) {
219
- 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--;
220
386
  }
221
- SMath.round2 = round2;
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
- SMath.error = error;
241
- /**
242
- * Add up all the inputs.
243
- * If none are present, returns 0.
244
- * @param data An array of numeric inputs
245
- * @returns The sum total
246
- * @example
247
- * ```js
248
- * const y = SMath.sum([1, 2, 3]); // 6
249
- * ```
250
- */
251
- function sum(data) {
252
- 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);
253
424
  }
254
- SMath.sum = sum;
255
- /**
256
- * Multiply all the inputs.
257
- * If none are present, returns 1.
258
- * @param data An array of numeric inputs
259
- * @returns The product
260
- * @example
261
- * ```js
262
- * const y = SMath.prod([2, 2, 3, 5]); // 60
263
- * ```
264
- */
265
- function prod(data) {
266
- 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 });
267
441
  }
268
- SMath.prod = prod;
269
- /**
270
- * Compute the average, or mean, of a set of numbers.
271
- * @param data An array of numeric inputs
272
- * @returns The average, or mean
273
- * @example
274
- * ```js
275
- * const y = SMath.avg([1, 2, 4, 4]); // 2.75
276
- * ```
277
- */
278
- function avg(data) {
279
- 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;
280
464
  }
281
- SMath.avg = avg;
282
- /**
283
- * Compute the median of a set of numbers.
284
- * @param data An array of numeric inputs
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
- return avg([data[data.length / 2 - 1], data[data.length / 2]]);
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
- if (max > 0) {
384
- max++;
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
- SMath.rnorm = rnorm;
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
- SMath.rdist = rdist;
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
- SMath.shuffle = shuffle;
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;
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
- // Check the limit approaching from the right
484
- if (Number.isFinite(right1) && Number.isFinite(right2)) {
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
- return NaN;
492
+ right = avg([right1, right2]);
516
493
  }
517
494
  }
518
- SMath.lim = lim;
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
- SMath.differentiate = differentiate;
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
- SMath.integrate = integrate;
552
- /**
553
- * Convert an arbitrary decimal number into a simplified fraction (or ratio).
554
- * See `mixed()` for instructions on how to break out the whole number part.
555
- * @param n The decimal number to convert
556
- * @param epsilon Maximum absolute error
557
- * @returns An object containing the fraction's numerator and denominator
558
- * @example
559
- * ```js
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
- SMath.rat = rat;
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
- SMath.mixed = mixed;
594
- })(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
+ }