2 이상의 숫자를 입력받았을 때, 해당하는 숫자까지의 소수를 순차적으로 나열하는 함수를 만드는 문제가 주어졌습니다. 소수가 무엇인지에 관해서는 소수에 관해 정리되어있는 위키백과를 참고하시면 되겠습니다.
https://ko.wikipedia.org/wiki/%EC%86%8C%EC%88%98_%28%EC%88%98%EB%A1%A0%29
열심히 코드를 작성해보니 다음과 같은 코드가 작성되었네요.
01 function listPrimes(num) {
02 let result = '2';
03 let prime = true;
04 for (let i = 3; i <= num; i += 2) {
05 for (let j = 3; j <= parseInt(Math.sqrt(i)); j += 2) {
06 if (i % j === 0) {
07 prime = false;
08 break;
09 }
10 }
11 if (prime) {
12 result = result + `-${i}`;
13 }
14 } return result;
15 }
언뜻 보기에는 큰 문제가 없어보입니다. 하지만 콘솔에서 돌려보면 아무리 큰 숫자를 넣어도 7 이상의 소수를 반환하지 않는다는 걸 알 수 있죠.
어디엔가 문제가 있습니다. 네 바로 3번째 줄에 있는 prime 변수의 위치가 문제인데요. 과연 왜 그런지 이 코드를 차근차근 훑어보도록 하겠습니다.
11이 함수의 인자로 들어왔다고 가정해보겠습니다. listPrimes(11) 이 되겠네요.
바깥의 i 반복문이 3에서부터 반복을 시작합니다. 그 다음에 위치한 내부의 j 반복문도 3에서부터 시작하죠. 3, 5, 7이 될 때까지 코드가 무리 없이 작동합니다.
이제 9라는 숫자가 소수인지를 테스트하기 시작합니다. 9의 제곱근은 3이죠. 9를 3으로 나누어보니 나머지가 0이 되면서 6번째 줄의 if 문의 조건이 충족되었습니다. 조건이 충족되면서 if 문은 prime 변수에 false 값을 할당하고 break 를 만나 종료됩니다.
문제는 prime 이라는 변수가 반복문 내부가 아닌 바깥에 선언되어 있다는 점입니다. 바꾸어 할당한 false 값이 이제는 기본값이 되어버렸습니다. prime 변수를 true 값으로 다시 바꾸어 할당하는 다른 구문이 반복문 내부에 없기 때문에. 9 이상의 홀수부터는 소수인지를 판별하는 반복문이 더 이상 의도한대로 작동할 수 없게 되었습니다.
해결방법은 의외로 간단합니다. 3번과 4번 줄의 위치를 서로 바꿔주는 것이죠. i 반복문 내부에서 prime 변수를 선언하면 됩니다.
01 function listPrimes(num) {
02 let result = '2';
03 for (let i = 3; i <= num; i += 2) {
04 let prime = true;
05 for (let j = 3; j <= parseInt(Math.sqrt(i)); j += 2) {
06 if (i % j === 0) {
07 prime = false;
08 break;
09 }
10 }
11 if (prime) {
12 result = result + `-${i}`;
13 }
14 } return result;
15 }
이렇게 바꾸어주는 것만으로도 이제 코드는 정상적으로 우리가 원하는 결과를 도출하게 됩니다. i = 9 일 때 false 값이 할당되었다 하더라도, 그 다음 i 반복문에서 prime 변수에 다시 true 값을 할당하기 때문입니다.
처음의 코드도 문법적으로는 아무런 오류가 없기 때문에 오류의 출력 없이 정상적으로 동작하지만, 우리가 기대하는 값을 제공해주지는 않습니다. 문법적으로 오류가 없을수록 무엇이 문제인지를 찾기란 더욱 어려워지는 것 같습니다.
고작 한 줄 차이로 위치한 변수가 코드를 좌지우지 할 수 있다는 것을 알게 되었으니, 이 경험이 앞으로 코드를 짤 때에도 도움이 될 것 같습니다. 이 글을 보시는 여러분에게도 도움이 되었으면 합니다.