math-utils-simple 2.1.0 → 4.0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "math-utils-simple",
3
- "version": "2.1.0",
3
+ "version": "4.0.0",
4
4
  "description": "A simple math utility library for npm",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -0,0 +1,9 @@
1
+ import cosineSimilarity from "./cosineSimilarity.js";
2
+
3
+ export default function angleBetweenVectors(a, b) {
4
+ const cosine = cosineSimilarity(a, b);
5
+
6
+ return Math.acos(
7
+ Math.min(1, Math.max(-1, cosine))
8
+ );
9
+ }
@@ -0,0 +1,13 @@
1
+ import dotProduct from "./dotProduct.js";
2
+ import vectorMagnitude from "./vectorMagnitude.js";
3
+
4
+ export default function cosineSimilarity(a, b) {
5
+ const magA = vectorMagnitude(a);
6
+ const magB = vectorMagnitude(b);
7
+
8
+ if (magA === 0 || magB === 0) {
9
+ throw new Error("Cannot calculate similarity for a zero vector.");
10
+ }
11
+
12
+ return dotProduct(a, b) / (magA * magB);
13
+ }
@@ -0,0 +1,15 @@
1
+ export default function crossProduct(a, b) {
2
+ if (!Array.isArray(a) || !Array.isArray(b)) {
3
+ throw new TypeError("Expected two arrays.");
4
+ }
5
+
6
+ if (a.length !== 3 || b.length !== 3) {
7
+ throw new Error("Cross product requires two 3-dimensional vectors.");
8
+ }
9
+
10
+ return [
11
+ a[1] * b[2] - a[2] * b[1],
12
+ a[2] * b[0] - a[0] * b[2],
13
+ a[0] * b[1] - a[1] * b[0],
14
+ ];
15
+ }
@@ -0,0 +1,15 @@
1
+ export default function cumulativeSum(array) {
2
+ if (!Array.isArray(array)) {
3
+ throw new TypeError("Expected an array.");
4
+ }
5
+
6
+ const result = [];
7
+ let sum = 0;
8
+
9
+ for (const value of array) {
10
+ sum += value;
11
+ result.push(sum);
12
+ }
13
+
14
+ return result;
15
+ }
@@ -0,0 +1,17 @@
1
+ export default function dotProduct(a, b) {
2
+ if (!Array.isArray(a) || !Array.isArray(b)) {
3
+ throw new TypeError("Expected two arrays.");
4
+ }
5
+
6
+ if (a.length !== b.length) {
7
+ throw new Error("Arrays must have the same length.");
8
+ }
9
+
10
+ let result = 0;
11
+
12
+ for (let i = 0; i < a.length; i++) {
13
+ result += a[i] * b[i];
14
+ }
15
+
16
+ return result;
17
+ }
@@ -0,0 +1,11 @@
1
+ export default function elementWiseAdd(a, b) {
2
+ if (!Array.isArray(a) || !Array.isArray(b)) {
3
+ throw new TypeError("Expected two arrays.");
4
+ }
5
+
6
+ if (a.length !== b.length) {
7
+ throw new Error("Arrays must have the same length.");
8
+ }
9
+
10
+ return a.map((value, index) => value + b[index]);
11
+ }
@@ -0,0 +1,13 @@
1
+ export default function elementWiseDivide(a, b) {
2
+ if (a.length !== b.length) {
3
+ throw new Error("Arrays must have the same length.");
4
+ }
5
+
6
+ return a.map((value, index) => {
7
+ if (b[index] === 0) {
8
+ throw new Error("Division by zero.");
9
+ }
10
+
11
+ return value / b[index];
12
+ });
13
+ }
@@ -0,0 +1,11 @@
1
+ export default function elementWiseMultiply(a, b) {
2
+ if (!Array.isArray(a) || !Array.isArray(b)) {
3
+ throw new TypeError("Expected two arrays.");
4
+ }
5
+
6
+ if (a.length !== b.length) {
7
+ throw new Error("Arrays must have the same length.");
8
+ }
9
+
10
+ return a.map((value, index) => value * b[index]);
11
+ }
@@ -0,0 +1,7 @@
1
+ export default function elementWiseSubtract(a, b) {
2
+ if (a.length !== b.length) {
3
+ throw new Error("Arrays must have the same length.");
4
+ }
5
+
6
+ return a.map((value, index) => value - b[index]);
7
+ }
@@ -0,0 +1,26 @@
1
+ export default function matrixMultiply(a, b) {
2
+ const rowsA = a.length;
3
+ const colsA = a[0].length;
4
+
5
+ const rowsB = b.length;
6
+ const colsB = b[0].length;
7
+
8
+ if (colsA !== rowsB) {
9
+ throw new Error("Matrix dimensions are incompatible.");
10
+ }
11
+
12
+ const result = Array.from(
13
+ { length: rowsA },
14
+ () => Array(colsB).fill(0)
15
+ );
16
+
17
+ for (let i = 0; i < rowsA; i++) {
18
+ for (let j = 0; j < colsB; j++) {
19
+ for (let k = 0; k < colsA; k++) {
20
+ result[i][j] += a[i][k] * b[k][j];
21
+ }
22
+ }
23
+ }
24
+
25
+ return result;
26
+ }
@@ -0,0 +1,23 @@
1
+ export default function movingAverage(array, window) {
2
+ if (!Array.isArray(array)) {
3
+ throw new TypeError("Expected an array.");
4
+ }
5
+
6
+ if (window <= 0 || window > array.length) {
7
+ throw new Error("Invalid window size.");
8
+ }
9
+
10
+ const result = [];
11
+
12
+ for (let i = 0; i <= array.length - window; i++) {
13
+ let sum = 0;
14
+
15
+ for (let j = 0; j < window; j++) {
16
+ sum += array[i + j];
17
+ }
18
+
19
+ result.push(sum / window);
20
+ }
21
+
22
+ return result;
23
+ }
@@ -0,0 +1,15 @@
1
+ export default function normalize(array) {
2
+ if (!Array.isArray(array)) {
3
+ throw new TypeError("Expected an array.");
4
+ }
5
+
6
+ const magnitude = Math.sqrt(
7
+ array.reduce((sum, value) => sum + value * value, 0)
8
+ );
9
+
10
+ if (magnitude === 0) {
11
+ throw new Error("Cannot normalize a zero vector.");
12
+ }
13
+
14
+ return array.map(value => value / magnitude);
15
+ }
@@ -0,0 +1,13 @@
1
+ import dotProduct from "./dotProduct.js";
2
+
3
+ export default function projectVector(a, b) {
4
+ const denominator = dotProduct(b, b);
5
+
6
+ if (denominator === 0) {
7
+ throw new Error("Cannot project onto a zero vector.");
8
+ }
9
+
10
+ const scalar = dotProduct(a, b) / denominator;
11
+
12
+ return b.map(value => scalar * value);
13
+ }
@@ -0,0 +1,7 @@
1
+ export default function scalarDivide(array, scalar) {
2
+ if (scalar === 0) {
3
+ throw new Error("Division by zero.");
4
+ }
5
+
6
+ return array.map(value => value / scalar);
7
+ }
@@ -0,0 +1,3 @@
1
+ export default function scalarMultiply(array, scalar) {
2
+ return array.map(value => value * scalar);
3
+ }
@@ -0,0 +1,20 @@
1
+ export default function transpose(matrix) {
2
+ if (matrix.length === 0) {
3
+ return [];
4
+ }
5
+
6
+ const rows = matrix.length;
7
+ const cols = matrix[0].length;
8
+
9
+ const result = [];
10
+
11
+ for (let col = 0; col < cols; col++) {
12
+ result[col] = [];
13
+
14
+ for (let row = 0; row < rows; row++) {
15
+ result[col][row] = matrix[row][col];
16
+ }
17
+ }
18
+
19
+ return result;
20
+ }
@@ -0,0 +1,11 @@
1
+ import vectorMagnitude from "./vectorMagnitude.js";
2
+
3
+ export default function vectorDistance(a, b) {
4
+ if (a.length !== b.length) {
5
+ throw new Error("Vectors must have the same length.");
6
+ }
7
+
8
+ const difference = a.map((value, index) => value - b[index]);
9
+
10
+ return vectorMagnitude(difference);
11
+ }
@@ -0,0 +1,5 @@
1
+ export default function vectorMagnitude(array) {
2
+ return Math.sqrt(
3
+ array.reduce((sum, value) => sum + value * value, 0)
4
+ );
5
+ }
package/src/index.js CHANGED
@@ -69,4 +69,39 @@ export { default as markup } from "./percentages/markup.js";
69
69
  export { default as profitPercentage } from "./percentages/profitPercentage.js";
70
70
  export { default as lossPercentage } from "./percentages/lossPercentage.js";
71
71
  export { default as margin } from "./percentages/margin.js";
72
- export { default as relativeChange } from "./percentages/relativeChange.js";
72
+ export { default as relativeChange } from "./percentages/relativeChange.js";
73
+
74
+ // STATISTICS
75
+ export { default as sum } from "./statistics/sum.js";
76
+ export { default as average } from "./statistics/average.js";
77
+ export { default as median } from "./statistics/median.js";
78
+ export { default as mode } from "./statistics/mode.js";
79
+ export { default as range } from "./statistics/range.js";
80
+ export { default as variance } from "./statistics/variance.js";
81
+ export { default as standardDeviation } from "./statistics/standardDeviation.js";
82
+ export { default as max } from "./statistics/max.js";
83
+ export { default as min } from "./statistics/min.js";
84
+ export { default as count } from "./statistics/count.js";
85
+ export { default as frequency } from "./statistics/frequency.js";
86
+ export { default as quartiles } from "./statistics/quartiles.js";
87
+ export { default as interQuartileRange } from "./statistics/interQuartileRange.js";
88
+
89
+ // ARRAYS
90
+ export { default as dotProduct } from "./arrays/dotProduct.js";
91
+ export { default as crossProduct } from "./arrays/crossProduct.js";
92
+ export { default as elementWiseAdd } from "./arrays/elementWiseAdd.js";
93
+ export { default as elementWiseSubtract } from "./arrays/elementWiseSubtract.js";
94
+ export { default as elementWiseMultiply } from "./arrays/elementWiseMultiply.js";
95
+ export { default as elementWiseDivide } from "./arrays/elementWiseDivide.js";
96
+ export { default as scalarMultiply } from "./arrays/scalarMultiply.js";
97
+ export { default as scalarDivide } from "./arrays/scalarDivide.js";
98
+ export { default as normalizeVector } from "./arrays/normalizeVector.js";
99
+ export { default as vectorMagnitude } from "./arrays/vectorMagnitude.js";
100
+ export { default as vectorDistance } from "./arrays/vectorDistance.js";
101
+ export { default as cosineSimilarity } from "./arrays/cosineSimilarity.js";
102
+ export { default as angleBetweenVectors } from "./arrays/angleBetweenVectors.js";
103
+ export { default as projectVector } from "./arrays/projectVector.js";
104
+ export { default as cumulativeSum } from "./arrays/cumulativeSum.js";
105
+ export { default as movingAverage } from "./arrays/movingAverage.js";
106
+ export { default as transpose } from "./arrays/transpose.js";
107
+ export { default as matrixMultiply } from "./arrays/matrixMultiply.js";
@@ -0,0 +1,13 @@
1
+ import sum from "./sum.js";
2
+
3
+ export default function average(array) {
4
+ if (!Array.isArray(array)) {
5
+ throw new TypeError("Expected an array.");
6
+ }
7
+
8
+ if (array.length === 0) {
9
+ throw new Error("Cannot calculate average of an empty array.");
10
+ }
11
+
12
+ return sum(array) / array.length;
13
+ }
@@ -0,0 +1,7 @@
1
+ export default function count(array) {
2
+ if (!Array.isArray(array)) {
3
+ throw new TypeError("Expected an array.");
4
+ }
5
+
6
+ return array.length;
7
+ }
@@ -0,0 +1,13 @@
1
+ export default function frequency(array) {
2
+ if (!Array.isArray(array)) {
3
+ throw new TypeError("Expected an array.");
4
+ }
5
+
6
+ const result = {};
7
+
8
+ for (const value of array) {
9
+ result[value] = (result[value] || 0) + 1;
10
+ }
11
+
12
+ return result;
13
+ }
@@ -0,0 +1,7 @@
1
+ import quartiles from "./quartiles.js";
2
+
3
+ export default function interQuartileRange(array) {
4
+ const { q1, q3 } = quartiles(array);
5
+
6
+ return q3 - q1;
7
+ }
@@ -0,0 +1,19 @@
1
+ export default function max(array) {
2
+ if (!Array.isArray(array)) {
3
+ throw new TypeError("Expected an array.");
4
+ }
5
+
6
+ if (array.length === 0) {
7
+ throw new Error("Cannot find maximum of an empty array.");
8
+ }
9
+
10
+ let largest = array[0];
11
+
12
+ for (const value of array) {
13
+ if (value > largest) {
14
+ largest = value;
15
+ }
16
+ }
17
+
18
+ return largest;
19
+ }
@@ -0,0 +1,18 @@
1
+ export default function median(array) {
2
+ if (!Array.isArray(array)) {
3
+ throw new TypeError("Expected an array.");
4
+ }
5
+
6
+ if (array.length === 0) {
7
+ throw new Error("Cannot calculate median of an empty array.");
8
+ }
9
+
10
+ const sorted = [...array].sort((a, b) => a - b);
11
+ const middle = Math.floor(sorted.length / 2);
12
+
13
+ if (sorted.length % 2 === 0) {
14
+ return (sorted[middle - 1] + sorted[middle]) / 2;
15
+ }
16
+
17
+ return sorted[middle];
18
+ }
@@ -0,0 +1,19 @@
1
+ export default function min(array) {
2
+ if (!Array.isArray(array)) {
3
+ throw new TypeError("Expected an array.");
4
+ }
5
+
6
+ if (array.length === 0) {
7
+ throw new Error("Cannot find minimum of an empty array.");
8
+ }
9
+
10
+ let smallest = array[0];
11
+
12
+ for (const value of array) {
13
+ if (value < smallest) {
14
+ smallest = value;
15
+ }
16
+ }
17
+
18
+ return smallest;
19
+ }
@@ -0,0 +1,38 @@
1
+ export default function mode(array) {
2
+ if (!Array.isArray(array)) {
3
+ throw new TypeError("Expected an array.");
4
+ }
5
+
6
+ if (array.length === 0) {
7
+ throw new Error("Cannot calculate mode of an empty array.");
8
+ }
9
+
10
+ const counts = new Map();
11
+
12
+ for (const value of array) {
13
+ counts.set(value, (counts.get(value) || 0) + 1);
14
+ }
15
+
16
+ let maxFrequency = 0;
17
+
18
+ for (const frequency of counts.values()) {
19
+ if (frequency > maxFrequency) {
20
+ maxFrequency = frequency;
21
+ }
22
+ }
23
+
24
+ // No mode if every value occurs equally often.
25
+ if (maxFrequency === 1) {
26
+ return [];
27
+ }
28
+
29
+ const modes = [];
30
+
31
+ for (const [value, frequency] of counts) {
32
+ if (frequency === maxFrequency) {
33
+ modes.push(value);
34
+ }
35
+ }
36
+
37
+ return modes.sort((a, b) => a - b);
38
+ }
@@ -0,0 +1,37 @@
1
+ import median from "./median.js";
2
+
3
+ export default function quartiles(array) {
4
+ if (!Array.isArray(array)) {
5
+ throw new TypeError("Expected an array.");
6
+ }
7
+
8
+ if (array.length === 0) {
9
+ throw new Error("Cannot calculate quartiles of an empty array.");
10
+ }
11
+
12
+ const sorted = [...array].sort((a, b) => a - b);
13
+
14
+ const q2 = median(sorted);
15
+
16
+ const middle = Math.floor(sorted.length / 2);
17
+
18
+ let lowerHalf;
19
+ let upperHalf;
20
+
21
+ if (sorted.length % 2 === 0) {
22
+ lowerHalf = sorted.slice(0, middle);
23
+ upperHalf = sorted.slice(middle);
24
+ } else {
25
+ lowerHalf = sorted.slice(0, middle);
26
+ upperHalf = sorted.slice(middle + 1);
27
+ }
28
+
29
+ const q1 = median(lowerHalf);
30
+ const q3 = median(upperHalf);
31
+
32
+ return {
33
+ q1,
34
+ q2,
35
+ q3,
36
+ };
37
+ }
@@ -0,0 +1,6 @@
1
+ import min from "./min.js";
2
+ import max from "./max.js";
3
+
4
+ export default function range(array) {
5
+ return max(array) - min(array);
6
+ }
@@ -0,0 +1,5 @@
1
+ import variance from "./variance.js";
2
+
3
+ export default function standardDeviation(array) {
4
+ return Math.sqrt(variance(array));
5
+ }
@@ -0,0 +1,7 @@
1
+ export default function sum(array) {
2
+ if (!Array.isArray(array)) {
3
+ throw new TypeError("Expected an array.");
4
+ }
5
+
6
+ return array.reduce((total, value) => total + value, 0);
7
+ }
@@ -0,0 +1,21 @@
1
+ import average from "./average.js";
2
+
3
+ export default function variance(array) {
4
+ if (!Array.isArray(array)) {
5
+ throw new TypeError("Expected an array.");
6
+ }
7
+
8
+ if (array.length === 0) {
9
+ throw new Error("Cannot calculate variance of an empty array.");
10
+ }
11
+
12
+ const mean = average(array);
13
+
14
+ let sum = 0;
15
+
16
+ for (const value of array) {
17
+ sum += (value - mean) ** 2;
18
+ }
19
+
20
+ return sum / array.length;
21
+ }