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);