
베르트랑 공준은 임의의 자연수 n에 대하여, n보다 크고, 2n보다 작거나 같은 소수는 적어도 하나 존재한다는 내용을 담고 있다.
이 명제는 조제프 베르트랑이 1845년에 추측했고, 파프누티 체비쇼프가 1850년에 증명했다.
예를 들어, 10보다 크고, 20보다 작거나 같은 소수는 4개가 있다. (11, 13, 17, 19) 또, 14보다 크고, 28보다 작거나 같은 소수는 3개가 있다. (17,19, 23)
자연수 n이 주어졌을 때, n보다 크고, 2n보다 작거나 같은 소수의 개수를 구하는 프로그램을 작성하시오.
const path = process.platform === 'linux' ? '/dev/stdin' : './input.txt';
const fs = require('fs');
let input = fs
.readFileSync(path)
.toString()
.split('\n')
.map((el) => parseInt(el)); // input = [1, 10, 13, 100, 1000, 10000, 100000, 0]
// 소수를 판별하는 함수
const isPrime = (n) => {
if (n < 2) return false; // 0과 1은 소수가 아니므로 제외
for (let i = 2; i <= parseInt(Math.sqrt(n)); i++) {
// 2부터 n의 제곱근(루트)까지 반복
if (n % i === 0) return false;
}
return true;
};
input.forEach((el) => {
if (el === 0) return; // 0일 경우, 입력 종료
let primeCnt = 0;
for (let i = el + 1; i <= 2 * el; i++) {
if (isPrime(i)) primeCnt++;
}
console.log(primeCnt);
});
소수를 판별하는 함수에는 에라토스테네스의 체 알고리즘을 사용했습니다.
const path = process.platform === 'linux' ? '/dev/stdin' : './input.txt';
const fs = require('fs');
let input = fs
.readFileSync(path)
.toString()
.split('\n')
.map((el) => parseInt(el));
const isPrime = (n) => {
if (n < 2) return false;
for (let i = 2; i <= parseInt(Math.sqrt(n)); i++) {
if (n % i === 0) return false;
}
return true;
};
for (let i = 0; i < input.length; i++) {
if (input[i] === 0) break;
let primeCnt = 0;
for (let j = input[i] + 1; j <= input[i] * 2; j++) {
if (isPrime(j)) primeCnt++;
}
console.log(primeCnt);
}
// 오답 풀이
input.forEach((el) => {
if (el === 0) return; // 입력값이 0일 경우, 반복을 종료
let primeCnt = 0;
for (let i = el + 1; i <= 2 * el; i++) {
if (isPrime(i)) primeCnt++;
}
console.log(primeCnt);
});
// 정답 풀이
for (let i = 0; i < input.length - 1; i++) {
let primeCnt = 0;
for (let j = input[i] + 1; j <= input[i] * 2; j++) {
if (isPrime(j)) primeCnt++;
}
console.log(primeCnt);
}
두 코드의 차이점은 반복문을 각각 forEach와 for로 작성한 것 뿐입니다.
다른 분들의 풀이와 비교해 보아도, 로직에 이상은 없는 것 같은데 forEach를 사용하면 계속 오답처리 되는 것이 의아하여 검색을 해 보니
forEach() 는 반복문이 아니라 인자로 콜백 함수를 전달받는 메서드기 때문에, return 명령은 루프 진행에 아무런 영향을 끼치지 않습니다.
(반복문을 탈출하는 break문 의도로 사용하였으나, continue 처럼 동작)
따라서, 단순 순회가 아닌 반복문 내에서 제어가 필요한 로직일 경우에는 for문을 사용해야 함에 주의해야 합니다.