다음 소스 코드는 http://www.daniweb.com/code/snippet808.html 에서 볼 수 있는 (주어진 범위 안에서) 소수(prime number, 북한 용어로는 씨수) 찾기 C++ 소스 코드이다.
 

  1. # include<iostream.h>
  2. # include<math.h>
  3. void main()
  4. {
  5.     int flag=0;
  6.     unsigned long l, h, temp;
  7.     cout<<"Enter the lower limit:"; cin>>l;
  8.     cout<<"Enter the higher limit:"; cin>>h;
  9.     if(l%2==0)
  10.     {
  11.          if(l==2) cout<<"2\t";
  12.          l++; //taking only odd no
  13.     }
  14.      for(;l<=h;l+=2, flag=0)
  15.      {
  16.           temp=sqrt(l);
  17.           if(temp%2==0) temp++; //taking only odd no
  18.           for(; temp>2; temp--)
  19.          {
  20.              if(l%temp==0)
  21.              {
  22.                  flag=1;
  23.                  break;
  24.               }
  25.          }
  26.          if(flag==0) cout<<l<<"\t";
  27.     }
  28. }

우선 위의 코드를 파이썬 소스 코드 처럼 들여쓰기 규칙을 엄격히 적용하여 아래 처럼 재작성하였다.


  1. #include <iostream.h>
  2. # include <math.h>
  3. void main() {
  4.     int flag = 0;
  5.     unsigned long l, h, temp;
  6.     cout << "Enter the lower limit: ";
  7.     cin >> l;
  8.     cout << "Enter the upper limit: ";
  9.     cin >> h;
  10.     if (l % 2 == 0) {
  11.          if (l == 2)
  12.              cout << "2\t";
  13.          l++;    //  Taking only odd numbers.
  14.     }
  15.     for (; l <= h; l += 2, flag = 0) {
  16.         temp = sqrt(l);
  17.         if (temp % 2 == 0)
  18.            temp++;    //  Taking only odd numbers.
  19.         for (; temp > 2; temp--) {
  20.            if (l % temp == 0) {
  21.                flag = 1;
  22.                break;
  23.            }
  24.        }
  25.        if (flag == 0)
  26.            cout << l << "\t";
  27.     }
  28. }

하지만 아직 표준 C++에 맞지 않으므로 더 고쳐 보았다.

  1. #include <iostream>
  2. #include <cmath>
  3. using namespace std;
  4. void main() {
  5.     int flag = 0;
  6.     unsigned long l, h, temp;
  7.     cout << "Enter the lower limit: ";
  8.     cin >> l;
  9.     cout << "Enter the upper limit: ";
  10.     cin >> h;
  11.     if (l % 2 == 0) {
  12.          if (l == 2)
  13.              cout << "2\t";
  14.          l++;    //  Taking only odd numbers.
  15.     }
  16.     for (; l <= h; l += 2, flag = 0) {
  17.         temp = sqrt(l);
  18.         if (temp % 2 == 0)
  19.            temp++;    //  Taking only odd numbers.
  20.         for (; temp > 2; temp--) {
  21.            if (l % temp == 0) {
  22.                flag = 1;
  23.                break;
  24.            }
  25.        }
  26.        if (flag == 0)
  27.            cout << l << "\t";
  28.     }
  29. }

이제 컴파일도 잘 되고 실행도 잘 될 것이다.
그러나 중요한 것은 알고리즘이다. 즉 소수인지 아닌지 확인하는 과정이 최적화되어 있느냐의 문제이다. 위의 소소 코드에서 27~32째 줄의 for 반복문 부분을 살펴보자,

            for (; temp > 2; temp--) {
               if (l % temp == 0) {
                   flag = 1;
                   break;
               }
          }

예를 들어 l =  3*1999993 = 5999979 인 경우 sqrt(5999979) ≒ 2449.5 이므로,
for 반복문을 시작하면서 temp = 2995 되고 t = 3 이 될 때 까지 무려 1496번을 반복하게 된다.
이 반복문 안의 나눗셈 과정  l % temp 부분을 l % 3 부터 시작하여 l % 5, l % 7, l % 9 ... 이런 식으로 증가시키면서 반복하는 과정으로 진행한다면, l =  3*1999993 = 5999979 인 경우 ㅣ% 3 = 0 이므로 더 이상 반복하지 않고 바로 반복문을 탈출하고 5999979는 소수가 아니라고 판정내린다.

이런 이유로 인하여, 위 소스 코드를 리팩토링하여 다음 처럼 수정하였다.


  1. #include <iostream>
  2. #include <cmath>
  3. using namespace std;
  4. void main() {
  5.     int flag = 0;
  6.     unsigned long l, h, j, temp;
  7.     cout << "Enter the lower limit: ";
  8.     cin >> l;
  9.     cout << "Enter the upper limit: ";
  10.     cin >> h;
  11.     if (l % 2 == 0) {
  12.          if (l == 2)
  13.              cout << "2\t";
  14.          l++;    //  Taking only odd numbers.
  15.     }
  16.     for (; l <= h; l += 2, flag = 0) {
  17.         temp = sqrt(l);
  18.         if (temp % 2 == 0)
  19.            temp++;    //  Taking only odd numbers.
  20.         for (j = 3L; j <= temp; j += 2L) {
  21.            if (l % j == 0L) {
  22.                flag = 1;
  23.                break;
  24.            }
  25.        }
  26.        if (flag == 0)
  27.            cout << l << "\t";
  28.     }
  29. }


 
컴파일> cl /GX findPrimes.cpp

실행> findPrimes
Enter the lower limit: 200
Enter the upper limit: 500
211     223     227     229     233     239     241     251     257     263
269     271     277     281     283     293     307     311     313     317
331     337     347     349     353     359     367     373     379     383
389     397     401     409     419     421     431     433     439     443
449     457     461     463     467     479     487     491     499



Creative Commons License


Posted by Scripter
,