I want to have a code that finds amicable numbers in a certain range, but it only outputs one amicable number instead of all amicable numbers in that range.
How can I solve it? I think it may be a scope error.
Amicable numbers are a pair of numbers that the sum of all the divisors of the first number equals the second number, and the sum of the divisors of the second number equals the first number.
Here is my code:
let sum1 = 1; let sum2 = 1; for (let num1 = 3; num1 < 1300; num1++) { for (let num2 = 3; num2 < 1300; num2++) { for (let div1 = 2; div1 < num1; div1++) { if (num1 % div1 === 0) { sum1 += div1 } } for (let div2 = 2; div2 < num2; div2++) { if (num2 % div2 === 0) { sum2 += div2 } } if (num1 === sum2 && sum1 === num2) { console.log(num1 + " and " + num2 + " are amicable numbers!") } } }
Advertisement
Answer
Your code is very inefficient, having to calculate the sum of the divisors on every iterartion – even though you have previously calculated the sum of divisors for this number.
I tend to find it easier to think about this sort of problem in multiple steps. Step 1, calculate the sum of divisors for any given number:
const sumDivisors = num => { let res = 0; for(let i=1;i<num;i++) if( (num % i) == 0) res += i return res; }
Step 2, gather the numbers in the desired range and all their sums of divisors
var divisors = new Array(1300).fill(0).map( (_,i) => i) .reduce( (acc,num) => ({...acc, [num]: sumDivisors(num)}))
The above gives you an object with num
as the key and sum
(of divisors) as the value.
{ "1": 0, "2": 1, "3": 1, "4": 3, "5": 1, "6": 6, "7": 1, "8": 7, .. etc }
Step3, look for any item in the list where
- key less than value (this also covers key != value and stops you getting both ways in the result ie 220,284 & 284,220)
- value matches another key
Put it all together you get the below code which gives the expected results
const sumDivisors = num => { let res = 0; for(let i=1;i<num;i++) if( (num % i) == 0) res += i return res; } var divisors = new Array(1300).fill(0).map( (_,i) => i) .reduce( (acc,num) => ({...acc, [num]: sumDivisors(num)})) var amicable = Object.entries(divisors) .filter( ([num,sum]) => num < sum && divisors[sum] == num); for(let [num1,num2] of amicable) console.log(num1 + " and " + num2 + " are amicable numbers!")
You may like to compare the performance difference here between your original code (fixed to work) and the code in this answer: https://jsbench.me/jekosj89v4/1 The improvement in speed is a factor of 1000