Updated to use either performance.now()
or process.hrtime.bigint()
. Same picture, so it isn’t the timing method. I’m still not sure what the difference is.
Updated Code
// ---------------------------------------------------
// Timing methodology
// ---------------------------------------------------
const performance = require('perf_hooks').performance;
// USE_PERF
// true: use performance.now()
// false: use process.hrtime.bigint()
const USE_PERF = true;
// ---------------------------------------------------
// Recursive variant
// ---------------------------------------------------
function sumFibsRecursive(num) {
function fibs(i) {
if (i < 3) return 1;
return fibs(i-1) + fibs(i-2);
}
let sum = 2;
let i = 3;
let fn = fibs(i);
while (fn <= num) {
if (fn % 2) sum += fn;
i++;
fn = fibs(i);
}
return sum;
}
// ---------------------------------------------------
// Store two variant
// ---------------------------------------------------
function sumFibsTwo(num) {
let sum = 2;
let f0 = 1;
let f1 = 2;
while (f1 <= num) {
if (f1 % 2) sum += f1;
f1 = f0 + f1;
f0 = f1 - f0;
}
return sum;
}
// ---------------------------------------------------
// Store two variant
// ---------------------------------------------------
function sumFibsDestructure(num) {
let sum = 2;
let f0 = 1;
let f1 = 2;
while (f1 <= num) {
if (f1 % 2) sum += f1;
f1 = f0 + f1;
f0 = f1 - f0;
}
return sum;
}
// ---------------------------------------------------
// Store all variant
// ---------------------------------------------------
function sumFibsAll(num) {
let sum = 2;
const fn = [1,1];
let i = 2
while (fn[i - 1] <= num) {
fn[i] = fn[i - 1] + fn[i - 2];
if (fn[i] % 2 && fn[i] <= num) {
sum += fn[i];
}
i++;
}
return sum
}
// ---------------------------------------------------
// Store all variant, improved
// ---------------------------------------------------
function sumFibsAllFast(num) {
let sum = 2;
let fn = [1, 1, 2];
let i = 2;
while (fn[i] <= num) {
if (fn[i] % 2) sum += fn[i];
fn[i+1] = fn[i] + fn[i-1];
i++;
}
return sum;
}
// ---------------------------------------------------
// Test cases
// ---------------------------------------------------
const numVariants = 5;
const variants = [
sumFibsRecursive,
sumFibsTwo,
sumFibsDestructure,
sumFibsAll,
sumFibsAllFast,
];
const variantNames = [
"Recursion, no tricks",
"Store current two values",
"Store current two values, with destructuring",
"Store entire array",
"Store entire array, reduced OPs",
]
// ---------------------------------------------------
// Timing function
// ---------------------------------------------------
function timeMe(func, num) {
let time = 0, result = 0;
if (USE_PERF) {
t0 = performance.now();
result = func(num);
t1 = performance.now();
time = Number(t1 - t0);
} else {
t0 = process.hrtime.bigint();
result = func(num);
t1 = process.hrtime.bigint();
time = Number(t1 - t0);
}
// Note: Capturing and returning result may prevent JS
// from optimizing out parts of the code
return {time, result};
}
// ---------------------------------------------------
// T-table values
// ---------------------------------------------------
tValues = [
12.71,
4.303,
3.182,
2.776,
2.571,
2.447,
2.365,
2.306,
2.262,
2.228,
2.201,
2.179,
2.16,
2.145,
2.131,
2.12,
2.11,
2.101,
2.093,
2.086,
2.08,
2.074,
2.069,
2.064,
2.06,
2.056,
2.052,
2.048,
2.045,
2.042,
2.04,
2.037,
2.035,
2.032,
2.03,
2.028,
2.026,
2.024,
2.023,
2.021,
2.02,
2.018,
2.017,
2.015,
2.014,
2.013,
2.012,
2.011,
2.01,
2.009,
2.004,
2,
1.997,
1.994,
1.992,
1.99,
1.988,
1.987,
1.985,
1.984,
]
// ---------------------------------------------------
// Multiple test runs
// ---------------------------------------------------
const numCases = 8;
for (let c = 0; c < numCases; c++) {
let sum = 0;
const numRuns = 25;
let times = [[], [], [], [], []];
const testNum = 20000*(2**c);
// Summary
console.log();
console.log("Test case " + c);
console.log(" - Test number : " + testNum);
console.log(" - Number runs : " + numRuns);
// Call once and throw away result
for (let i = 0; i < numVariants; i++) {
timeMe(variants[i], testNum);
}
// Time multiple times
for (let i = 0; i < numRuns; i++) {
// Each variant
for (let j = 0; j < numVariants; j++) {
let {time, result} = timeMe(variants[j], testNum);
sum += result;
times[j][i] = time;
}
}
console.log(" - Validity check : " +
(
sum === numRuns*numVariants*sumFibsDestructure(testNum) ?
"\"Valid data\"" :
"\"Invalid data\""
)
);
// Output timing data
for (let i = 0; i < numVariants; i++) {
// Compute stats
const minTime = Math.min(...times[i]);
const maxTime = Math.max(...times[i]);
const avgTime = times[i].reduce((sum, item) => sum + item, 0) / numRuns;
const variance = times[i].reduce((sumSqDiff, item) => sumSqDiff + (avgTime - item)**2, 0) / numRuns;
const stdDev = Math.sqrt(variance);
// Output
console.log();
console.log(" - Variant : \"" + variantNames[i] + "\"");
console.log(" Statistics:");
console.log(" Average Time : " + avgTime);
console.log(" Minimum Time : " + minTime);
console.log(" Maximum Time : " + maxTime);
console.log(" Standard Deviation : " + stdDev);
console.log(" Variance : " + variance);
console.log(" Confidence Interval : [" +
(avgTime - tValues[numRuns-1]*stdDev).toFixed(5) +
", " +
avgTime.toFixed(5) +
", " +
(avgTime + tValues[numRuns-1]*stdDev).toFixed(5) +
"]"
);
}
}
Repl
https://replit.com/@jeremylt/GrotesqueNoteworthySpheres#index.js
Sample Output - `performance.now()`
Test case 7
- Test number : 2560000
- Number runs : 25
- Validity check : "Valid data"
- Variant : "Recursion, no tricks"
Statistics:
Average Time : 583.5548874399066
Minimum Time : 499.1479770001024
Maximum Time : 699.4015239998698
Standard Deviation : 50.04558719776144
Variance : 2504.560797968744
Confidence Interval : [480.46098, 583.55489, 686.64880]
- Variant : "Store current two values"
Statistics:
Average Time : 0.006078719869256019
Minimum Time : 0.0032979995012283325
Maximum Time : 0.047867000102996826
Standard Deviation : 0.00855423692134246
Variance : 0.00007317496930645854
Confidence Interval : [-0.01154, 0.00608, 0.02370]
- Variant : "Store current two values, with destructuring"
Statistics:
Average Time : 0.002953760176897049
Minimum Time : 0.002258000895380974
Maximum Time : 0.0036149993538856506
Standard Deviation : 0.0005050616597111463
Variance : 2.550872801101778e-7
Confidence Interval : [0.00191, 0.00295, 0.00399]
- Variant : "Store entire array"
Statistics:
Average Time : 0.019145680144429206
Minimum Time : 0.01250000111758709
Maximum Time : 0.03777799941599369
Standard Deviation : 0.007709820181039697
Variance : 0.000059441327223966994
Confidence Interval : [0.00326, 0.01915, 0.03503]
- Variant : "Store entire array, reduced OPs"
Statistics:
Average Time : 0.018998439833521844
Minimum Time : 0.010862000286579132
Maximum Time : 0.03238900005817413
Standard Deviation : 0.00672966936878334
Variance : 0.000045288449813140766
Confidence Interval : [0.00514, 0.01900, 0.03286]
Sample Output - `process.hrtime.bigint()`
Test case 7
- Test number : 2560000
- Number runs : 25
- Validity check : "Valid data"
- Variant : "Recursion, no tricks"
Statistics:
Average Time : 670159210.08
Minimum Time : 557879905
Maximum Time : 1124115614
Standard Deviation : 126200359.26571509
Variance : 15926530678795560
Confidence Interval : [410186469.99263, 670159210.08000, 930131950.16737]
- Variant : "Store current two values"
Statistics:
Average Time : 3850.28
Minimum Time : 2764
Maximum Time : 5483
Standard Deviation : 838.2283946514816
Variance : 702626.8415999999
Confidence Interval : [2123.52951, 3850.28000, 5577.03049]
- Variant : "Store current two values, with destructuring"
Statistics:
Average Time : 3040.08
Minimum Time : 1957
Maximum Time : 6247
Standard Deviation : 1189.4442709097386
Variance : 1414777.6735999999
Confidence Interval : [589.82480, 3040.08000, 5490.33520]
- Variant : "Store entire array"
Statistics:
Average Time : 19542.96
Minimum Time : 12712
Maximum Time : 94988
Standard Deviation : 15675.536516444981
Variance : 245722445.07840005
Confidence Interval : [-12748.64522, 19542.96000, 51834.56522]
- Variant : "Store entire array, reduced OPs"
Statistics:
Average Time : 13881.92
Minimum Time : 10516
Maximum Time : 18922
Standard Deviation : 2770.221116373204
Variance : 7674125.0336
Confidence Interval : [8175.26450, 13881.92000, 19588.57550]
By the way, this has been a fun and interesting diversion, so thank you.