-
Notifications
You must be signed in to change notification settings - Fork 226
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Implement log average * Fix message
- Loading branch information
Showing
6 changed files
with
103 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/** | ||
* The [log average](https://en.wikipedia.org/wiki/https://en.wikipedia.org/wiki/Geometric_mean#Relationship_with_logarithms) | ||
* is an equivalent way of computing the geometric mean of an array suitable for large or small products. | ||
* | ||
* It's found by calculating the average logarithm of the elements and exponentiating. | ||
* | ||
* @param {Array<number>} x sample of one or more data points | ||
* @returns {number} geometric mean | ||
* @throws {Error} if x is empty | ||
* @throws {Error} if x contains a negative number | ||
*/ | ||
function logAverage(x) { | ||
if (x.length === 0) { | ||
throw new Error("logAverage requires at least one data point"); | ||
} | ||
|
||
let value = 0; | ||
for (let i = 0; i < x.length; i++) { | ||
if (x[i] < 0) { | ||
throw new Error( | ||
"logAverage requires only non-negative numbers as input" | ||
); | ||
} | ||
value += Math.log(x[i]); | ||
} | ||
|
||
return Math.exp(value / x.length); | ||
} | ||
|
||
export default logAverage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/* eslint no-shadow: 0 */ | ||
|
||
const test = require("tap").test; | ||
const ss = require("../"); | ||
|
||
test("log average", function (t) { | ||
t.test("cannot calculate for empty lists", function (t) { | ||
t.throws(function () { | ||
ss.logAverage([]); | ||
}); | ||
t.end(); | ||
}); | ||
|
||
t.test("cannot calculate for lists with negative numbers", function (t) { | ||
t.throws(function () { | ||
ss.logAverage([-1]); | ||
}); | ||
t.end(); | ||
}); | ||
|
||
t.test("does not overflow for large products", function (t) { | ||
const value = 1000; | ||
const array = []; | ||
for (let i = 0; i < 100; i++) { | ||
array.push(value); | ||
} | ||
if (!isFinite(ss.logAverage(array))) { | ||
t.fail("log average failed for large product"); | ||
} | ||
t.end(); | ||
}); | ||
|
||
t.test("does not underflow for small products", function (t) { | ||
const value = 0.001; | ||
const array = []; | ||
for (let i = 0; i < 100; i++) { | ||
array.push(value); | ||
} | ||
if (ss.logAverage(array) === 0) { | ||
t.fail("log average failed for small product"); | ||
} | ||
t.end(); | ||
}); | ||
|
||
t.test("agrees with geometricMean", function (t) { | ||
const arr = []; | ||
for (let i = 0; i < 10; i++) { | ||
arr.push(Math.exp(Math.random())); | ||
} | ||
if (Math.abs(ss.logAverage(arr) - ss.geometricMean(arr)) > ss.epsilon) { | ||
t.fail("log average and geometric mean are not equal"); | ||
} | ||
t.end(); | ||
}); | ||
|
||
t.test("equals zero if array contains zero", function (t) { | ||
if (ss.logAverage([0, 1, 2]) !== 0) { | ||
t.fail("log average of array containing zero is not zero"); | ||
} | ||
t.end(); | ||
}); | ||
t.end(); | ||
}); |
This file was deleted.
Oops, something went wrong.