August 27th 2018
이전에 특정 수의 가장 큰 소인수를 찾는 방법을 포스팅했었습니다. 이번에는 주어진 수 n까지 소수의 개수 찾는 방법에 대해 알아보도록 하겠습니다.
Contents
위에서 소수의 정의에 대해 살펴봤습니다. 이를 기준으로 이번에는 특정 수가 주어졌을 때, 이 수가 소수인지 아닌지 확인하는 방법에 대해 알아보도록 하겠습니다. 별도의 함수를 작성해 소수인면 true, 소수가 아니면 false를 반환하도록 작성하고자 합니다.
function isPrime(n) {
if (n === 2) {
// 숫자 2는 소수이므로 true를 반환함.
return true;
}
if (n < 2 || !(n % 2)) {
// 0, 1과 2의 배수는 false로 반환함.
return false;
}
for (let i = 3; i <= Math.sqrt(n); i += 2) {
// 3부터 루트 n 까지의 숫자 중 나누어 떨어지면 false 반환함.
if (n % i === 0) {
return false;
}
}
return true;
}
가장 간단한 방법은 2부터 '특정 수 - 1'까지 반복문을 실행 시킵니다. 반복문 중 해당하는 수가 어떠한 수로 나누어 떨어지면 소수가 아닙니다. 이때, 위에서 만든 isPrime 함수를 사용할 수도 있을 것입니다.
하지만, 이 방식의 문제점은 숫자 n이 커질수록 연산 횟수가 기하급수적으로 증가합니다. 이 문제를 해결하기 위해서는 다른 방법을 이용해야 합니다. 저는 여러 방법 중 소수의 개수를 구할 때 많이 이용하는 에라토스테네스의 체를 이용해 해결하는 방법에 대해 학습하고자 합니다.
에라토스테네스의 체는 숫자 n까지의 소수의 개수를 구할 때, 가장 작은 소수부터 시작해 그 수의 배수를 제거해가며 소수의 개수를 구하는 방법입니다. 예를 들면, 2를 제외한 2의 배수를 제거하고, 그다음 3을 제외한 3의 배수를 제거, 5를 제외한 5의 배수를 제거해 가며 소수를 구하는 방법입니다. 이런 방식으로 문제를 풀면 체크해야하는 수의 범위를 현저히 줄일 수 있습니다. 다시 말해 컴퓨터의 연산 과정을 줄일 수가 있게 됩니다.
function solution(limit) {
const primes = [];
const bools = new Array(limit - 1).fill(true); // 배열의 index 0은 숫자 2를 대신하고 index 1은 숫자 3, index 2는 4를...
for (let i = 2; i < limit; i++) {
// 1은 소수가 아니기 때문에 반복문을 2부터 시작해 합성수의 값을 false로 변경함.
if (bools[i - 2]) {
for (let j = i * 2; j <= limit; j += i) {
bools[j - 2] = false;
}
}
}
for (let v = 0; v < bools.length; v++) {
// 소수로 남아있는 bools 배열의 요소만 취해, 소수만의 배열을 생성함.
if (bools[v]) {
primes.push(v + 2);
}
}
return primes;
}