Skip to content

Commit

Permalink
feat: add findLongestRecurringCycle algorithm (Problem 26)
Browse files Browse the repository at this point in the history
  • Loading branch information
gaye-lamine committed Oct 20, 2024
1 parent fd1d6e6 commit c6192d7
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 42 deletions.
25 changes: 5 additions & 20 deletions Project-Euler/Problem026.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@
* @see {@link https://projecteuler.net/problem=26}
*
* Find the value of denominator < 1000 for which 1/denominator contains the longest recurring cycle in its decimal fraction part.
*
* A unit fraction (1/denominator) either terminates or repeats. We need to determine the length of the repeating sequence (cycle)
* for each fraction where the denominator is between 2 and 999, and find the denominator that produces the longest cycle.
*/

/**
Expand All @@ -23,49 +20,37 @@ function findLongestRecurringCycle(limit) {
* @returns {number} The length of the recurring cycle in the decimal part of 1/denominator.
*/
function getRecurringCycleLength(denominator) {
// A map to store the position of each remainder encountered during division
const remainderPositions = new Map()
let numerator = 1 // We start with 1 as the numerator (as we're computing 1/denominator)
let position = 0 // This tracks the position of each digit in the decimal sequence
let numerator = 1
let position = 0

// Continue until the remainder becomes 0 (terminating decimal) or a cycle is found
while (numerator !== 0) {
// If the remainder has been seen before, we've found the start of the cycle
if (remainderPositions.has(numerator)) {
// The length of the cycle is the current position minus the position when the remainder first appeared
return position - remainderPositions.get(numerator)
}

// Record the position of this remainder
remainderPositions.set(numerator, position)

// Multiply numerator by 10 to simulate long division and get the next digit
numerator = (numerator * 10) % denominator
position++ // Move to the next digit position
position++
}

// If numerator becomes 0, it means the decimal terminates (no cycle)
return 0
}

let maxCycleLength = 0 // Store the maximum cycle length found
let denominatorWithMaxCycle = 0 // Store the denominator corresponding to the longest cycle
let maxCycleLength = 0
let denominatorWithMaxCycle = 0

// Iterate through each possible denominator from 2 up to (limit - 1)
for (let denominator = 2; denominator < limit; denominator++) {
// Calculate the cycle length for the current denominator
const cycleLength = getRecurringCycleLength(denominator)

// Update the maximum length and the corresponding denominator if a longer cycle is found
if (cycleLength > maxCycleLength) {
maxCycleLength = cycleLength
denominatorWithMaxCycle = denominator
}
}

// Return the denominator that has the longest recurring cycle
return denominatorWithMaxCycle
}

// Exporting the main function for use in other modules
export { findLongestRecurringCycle }
30 changes: 8 additions & 22 deletions Project-Euler/test/Problem026.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,13 @@ import { findLongestRecurringCycle } from '../Problem026'
* Tests for the findLongestRecurringCycle function.
*/
describe('findLongestRecurringCycle', () => {
// Test to check the basic case with a limit of 10
test('should return 7 for limit of 10', () => {
const result = findLongestRecurringCycle(10)
expect(result).toBe(7)
})

// Test to check with a limit of 1000
test('should return the correct value for limit of 1000', () => {
const result = findLongestRecurringCycle(1000)
expect(result).toBe(983) // The expected result is the denominator with the longest cycle
})

// Test with a smaller limit to validate behavior
test('should return 3 for limit of 4', () => {
const result = findLongestRecurringCycle(4)
expect(result).toBe(3)
})

// Test with a limit of 2, where there is no cycle
test('should return 0 for limit of 2', () => {
const result = findLongestRecurringCycle(2)
expect(result).toBe(0) // No cycle for fractions 1/1 and 1/2
it.each([
{ limit: 10, expected: 7 },
{ limit: 1000, expected: 983 }, // The denominator with the longest cycle for limit of 1000
{ limit: 4, expected: 3 },
{ limit: 2, expected: 0 } // No cycle for fractions 1/1 and 1/2
])('should return $expected for limit of $limit', ({ limit, expected }) => {
const result = findLongestRecurringCycle(limit)
expect(result).toBe(expected)
})
})

0 comments on commit c6192d7

Please sign in to comment.