Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import euclideanAlgorithmIterative from '../euclideanAlgorithmIterative';

describe('euclideanAlgorithmIterative', () => {
it('should handle widely separated safe integers', () => {
expect(euclideanAlgorithmIterative(Number.MAX_SAFE_INTEGER, 2)).toBe(1);
expect(euclideanAlgorithmIterative(2, Number.MAX_SAFE_INTEGER)).toBe(1);
expect(euclideanAlgorithmIterative(-Number.MAX_SAFE_INTEGER, 3)).toBe(1);
expect(euclideanAlgorithmIterative(2 ** 52, 2)).toBe(2);
});

it('should calculate GCD iteratively', () => {
expect(euclideanAlgorithmIterative(0, 0)).toBe(0);
expect(euclideanAlgorithmIterative(2, 0)).toBe(2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@ export default function euclideanAlgorithmIterative(originalA, originalB) {
let a = Math.abs(originalA);
let b = Math.abs(originalB);

// Subtract one number from another until both numbers would become the same.
// This will be out GCD. Also quit the loop if one of the numbers is zero.
while (a && b && a !== b) {
[a, b] = a > b ? [a - b, b] : [a, b - a];
// Each remainder replaces a whole sequence of repeated subtractions.
while (b !== 0) {
[a, b] = [b, a % b];
}

// Return the number that is not equal to zero since the last subtraction (it will be a GCD).
return a || b;
return a;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import leastCommonMultiple from '../leastCommonMultiple';

describe('leastCommonMultiple', () => {
it.each([
[549533988, 76324165],
[76324165, 549533988],
[-549533988, 76324165],
[549533988, -76324165],
])('should avoid overflowing the intermediate product for %i and %i', (a, b) => {
expect(leastCommonMultiple(a, b)).toBe(2747669940);
});

it('should find least common multiple', () => {
expect(leastCommonMultiple(0, 0)).toBe(0);
expect(leastCommonMultiple(1, 0)).toBe(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ import euclideanAlgorithm from '../euclidean-algorithm/euclideanAlgorithm';
*/

export default function leastCommonMultiple(a, b) {
return ((a === 0) || (b === 0)) ? 0 : Math.abs(a * b) / euclideanAlgorithm(a, b);
// Divide first so a safe integer result does not require an unsafe intermediate product.
return ((a === 0) || (b === 0)) ? 0 : Math.abs((a / euclideanAlgorithm(a, b)) * b);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import pascalTriangle from '../pascalTriangle';

describe('pascalTriangle', () => {
it('should preserve safe integer coefficients when intermediate products are larger', () => {
expect(pascalTriangle(57)[22]).toBe(3489348548829780);
expect(pascalTriangle(56)[28]).toBe(7648690600760440);

// Build independent rows using Pascal's addition identity.
let expected = [1];
for (let row = 1; row <= 56; row += 1) {
expected = [1, ...expected.slice(1).map((value, i) => value + expected[i]), 1];
expect(pascalTriangle(row)).toEqual(expected);
}
});

it('should calculate Pascal Triangle coefficients for specific line number', () => {
expect(pascalTriangle(0)).toEqual([1]);
expect(pascalTriangle(1)).toEqual([1, 1]);
Expand Down
8 changes: 6 additions & 2 deletions src/algorithms/math/pascal-triangle/pascalTriangle.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
/* eslint-env es2020 */
/**
* @param {number} lineNumber - zero based.
* @return {number[]}
*/
export default function pascalTriangle(lineNumber) {
const currentLine = [1];
let coefficient = BigInt(1);

const currentLineSize = lineNumber + 1;

for (let numIndex = 1; numIndex < currentLineSize; numIndex += 1) {
// See explanation of this formula in README.
currentLine[numIndex] = (currentLine[numIndex - 1] * (lineNumber - numIndex + 1)) / numIndex;
// See explanation of this formula in README. Keep the intermediate product
// exact even when it exceeds Number.MAX_SAFE_INTEGER before division.
coefficient = (coefficient * BigInt(lineNumber - numIndex + 1)) / BigInt(numIndex);
currentLine[numIndex] = Number(coefficient);
}

return currentLine;
Expand Down