152 lines
3.2 KiB
TypeScript
152 lines
3.2 KiB
TypeScript
const isEven = (n: number) => {
|
|
let even = true; // 0 is even
|
|
|
|
for (let i = 1; i <= n; i++) {
|
|
even = !even;
|
|
}
|
|
|
|
return even;
|
|
};
|
|
|
|
const sumOfEvenSquares = (upTo: number) => {
|
|
let sum = 0;
|
|
|
|
for (let i = 1; i <= upTo; i++) {
|
|
if (isEven(i)) {
|
|
sum += i * i;
|
|
}
|
|
}
|
|
|
|
return sum;
|
|
};
|
|
|
|
/**
|
|
* functional
|
|
*/
|
|
|
|
const isEvenHelper = (curr: number, max: number, previous = false) => {
|
|
if (curr === max) {
|
|
return !previous;
|
|
}
|
|
|
|
return isEvenHelper(curr + 1, max, !previous);
|
|
};
|
|
|
|
const isEvenFn = (n: number) => {
|
|
return isEvenHelper(0, n);
|
|
};
|
|
|
|
const map = (
|
|
transform: (x: number, ind: number) => number,
|
|
list: number[],
|
|
index = 0,
|
|
) => {
|
|
if (list.length === 0) {
|
|
return [];
|
|
}
|
|
const [head, ...tail] = list;
|
|
const transformed = transform(head, index);
|
|
|
|
return [transformed].concat(map(transform, tail, index + 1));
|
|
};
|
|
|
|
const filter = (predicate: (x: number) => boolean, list: number[]) => {
|
|
if (list.length === 0) {
|
|
return [];
|
|
}
|
|
|
|
const [head, ...tail] = list;
|
|
if (predicate(head)) {
|
|
return [head].concat(filter(predicate, tail));
|
|
}
|
|
return filter(predicate, tail);
|
|
};
|
|
|
|
const reduce = (
|
|
accumulation: (x: number, accumulator: number) => number,
|
|
accumulator: number,
|
|
list: number[],
|
|
) => {
|
|
if (list.length === 0) {
|
|
return accumulator;
|
|
}
|
|
|
|
const [head, ...tail] = list;
|
|
const newAccumulator = accumulation(head, accumulator);
|
|
return reduce(accumulation, newAccumulator, tail);
|
|
};
|
|
|
|
const curriedReduce = (
|
|
accumulation: (x: number, accumulator: number) => number,
|
|
) => {
|
|
return (accumulator: number) => {
|
|
const reduce = (list: number[]) => {
|
|
if (list.length === 0) {
|
|
return accumulator;
|
|
}
|
|
|
|
const [head, ...tail] = list;
|
|
const newAccumulator = accumulation(head, accumulator);
|
|
|
|
return curriedReduce(accumulation)(newAccumulator)(tail);
|
|
};
|
|
|
|
return reduce;
|
|
};
|
|
};
|
|
|
|
const sum = curriedReduce((x, acc) => x + acc)(0);
|
|
|
|
const sumOfEvenSquaresFn = (upTo: number) => {
|
|
const numbersUpTo = Array(upTo + 1)
|
|
.fill(0)
|
|
.map((_, i) => i);
|
|
const squares = numbersUpTo.filter((x) => isEvenFn(x)).map((x) => x * x);
|
|
|
|
return sum(squares);
|
|
};
|
|
|
|
/**
|
|
* test
|
|
*/
|
|
|
|
const assert = (predicate: () => boolean, message: string) => {
|
|
const start = performance.now();
|
|
|
|
console.log(message + "...");
|
|
const result = predicate();
|
|
|
|
const runtimeFmt = ` in ${(performance.now() - start).toFixed(5)}ms`;
|
|
if (result) {
|
|
console.log(" ... PASSED" + runtimeFmt);
|
|
return;
|
|
}
|
|
|
|
console.error(" ... FAILED" + runtimeFmt);
|
|
throw new Error("predicate failed for test: " + message);
|
|
};
|
|
|
|
/*
|
|
Σ(2i)^2 = 4 * Σ(i)^2 = 4 * (n * (n + 1) * (2 * n + 1)) / 6
|
|
*/
|
|
const constantTimeMathMagic = (x: number) => {
|
|
const n = Math.floor(x / 2); // even numbers
|
|
return (4 * (n * (n + 1) * (2 * n + 1))) / 6;
|
|
};
|
|
|
|
const test = (sumEvenSquarer: (x: number) => number) => {
|
|
assert(() => sumEvenSquarer(5) === 2 ** 2 + 4 ** 2, "up to 5");
|
|
assert(
|
|
() => sumEvenSquarer(10) === 2 ** 2 + 4 ** 2 + 6 ** 2 + 8 ** 2 + 10 ** 2,
|
|
"up to 10",
|
|
);
|
|
|
|
//assert(
|
|
// () => sumEvenSquarer(75_000) === constantTimeMathMagic(75_000),
|
|
// "up to 75,000",
|
|
//);
|
|
};
|
|
|
|
test(sumOfEvenSquares);
|
|
test(sumOfEvenSquaresFn);
|