5-1-나.산술 연산자

산술(Arithmetic) 연산자는 더하고 곱하고 빼고 나누는 가장 기본적이고 또한 가장 많이 사용되는 연산자이다. 초등학교때부터 배웠고 일상 생활에서도 늘상 사용하는 연산자이므로 더 이상의 상세한 설명이 필요치는 않을 것 같다. 연산자는 기호로 표시하는데 더하기와 빼기는 수학에서와 마찬가지로 +, - 기호를 사용한다. 곱하기는 보통 ´ 기호를 사용하지만 알파벳 X와 모양이 동일해서 *를 대신 사용한다. 그리고 나누기는 보통 ¸기호를 사용하는데 이 문자가 키보드에 없기 때문에 / 기호를 사용하여 분수 형태로 표현한다.

기호가 조금 다른 것 빼고는 학교에서 배운 것과 동일하되 다만 나눗셈을 하는 / 연산자에 대해서만 약간의 주의를 하면 된다. 이 연산자는 피연산자의 타입에 따라 연산의 결과가 달라지는 특징이 있다. 피연산자가 모두 정수형이면 결과도 정수형이 되고 피연산자중에 실수형이 있으면 결과도 실수형이 된다. 다음 예를 보자.

 

6/3                   // 결과는 2

3.0/2.0              // 결과는 1.5

3/2                   // 결과는 1

 

6을 3으로 나누면 결과는 당연히 2가 된다. 실수형 상수 3.0을 실수 2.0으로 나누면 1.5가 된다. 그러나 정수형 상수 3을 정수 2로 나누면 결과는 역시 정수형인 1이 되며 소수점 이하는 버려진다. 정수끼리의 나누기에 대한 결과는 정수형이기 때문에 소수점을 기억할 수 없는 것이다. 피연산자에 따라 계산 결과의 타입이 달라지는 것은 비단 나누기 연산자만 그런 것이 아니라 다른 산술 연산자도 마찬가지이기는 하다. 그러나 다른 연산자는 변수의 기억 용량을 넘어서는 오버플로우 문제는 있을지언정 최소한 버려지는 값은 없으므로 문제가 되지 않는 것이다. 다음 예제를 실행해 보자.

 

: intdivide

#include <Turboc.h>

 

void main()

{

     int score;

 

     score=86+65+92+88;

     printf("총점=%d, 평균=%d\n",score,score/4);

}

 

정수형 변수 score는 4과목 성적의 총점이며 암산해 보면 알겠지만 331의 값을 가진다. 총점에 대한 평균은 이 값을 과목수인 4로 나누면 쉽게 구할 수 있다. 실행 결과는 다음과 같다.

 

총점=331, 평균=82

 

평균이 82로 계산되었는데 실제 평균인 331/4는 82.75이지만 정수끼리의 나누기를 했기 때문에 0.75가 잘려 나간다. 원래 의도가 소수점 이하를 버릴 생각이었다면 이렇게 하는 것이 옳겠지만 만약 소수점까지 정확하게 출력하고 싶다면 정수 나눗셈을 해서는 안되며 다음과 같이 둘 중 하나를 실수형으로 바꿔야 한다.

 

printf("총점=%d, 평균=%f\n",score,score/4.);

 

4를 4.0 또는 4.으로 바꾸어 실수형 상수임을 명시했고 계산 결과가 실수형이므로 이 값을 받을 서식도 %f로 수정했다. 이제 결과가 제대로 출력될 것이다. 평균을 정수 단위까지만 구할 것인가 아니면 소수점 이하까지 정확하게 계산할 것인가에 따라 / 연산자를 잘 사용해야 한다. 겨우 0.75의 차이이지만 이 값이 이자율이나 주식 배당률같이 중요한 값이라면 실제 업무 환경에서는 이런 미세한 오차가 돌이킬 수 없는 결과를 초래할 수도 있다.

산술 연산자에는 사칙 연산자 4개가 있고 이외에 나머지 연산자 %도 산술 연산자로 분류된다. %는 두 연산자를 나눈 후 몫은 버리고 나머지만 취한다. 8%3 연산의 결과는 2가 되는데 8을 3으로 나누면 몫은 2인데 이 값은 버리고 나머지 2를 결과로 리턴한다. 10%4는 2가 되고 7%3은 1이 됨을 이해한다면 나머지 연산자는 다 이해한 것이다.

나머지 연산자는 굉장히 활용할 곳이 많다. 앞 장의 예제에서 어떤 수가 다른 수의 배수인지를 검사할 때 % 연산자를 이미 사용해 본 적이 있다. a%b가 0이라면 즉, a를 b로 나누었더니 나머지가 없다면 a는 b의 배수라고 할 수 있다. 어떤 수 k가 짝수인지 알고 싶다면 if (k%2==0) 조건으로 검사할 수 있는데 2로 나눈 나머지가 없다면 이 수는 짝수이다.

나머지 연산자는 피연산자로 정수만 취할 수 있으며 정수 나눗셈을 하고 결과도 정수로 돌려준다. 사실 나머지라는 연산 자체가 정수 범위에서만 의미가 있다. 만약 5%3이 실수 나눗셈을 한다면 몫은 1.666666이 될 것이고 나머지는 없을 것이다. % 연산자의 피연산자로 실수형을 사용하면 에러로 처리된다.

다음 예제는 앞장에서 만들어 보았던 #움직이기와 비슷한데 달팽이가 기어가는 모양의 애니메이션 효과를 낸다. 제어 변수 i가 짝수이면 __@ 이런 모양, 홀수이면 ^^@ 이런 모양으로 출력하는데 이때 홀짝 판별을 위해 나머지 연산자를 사용했다. 반복적인 루프에서 일정한 주기별로 다른 동작을 하고자 할 때 나머지 연산자를 사용하는데 세 가지 모양을 번갈아가며 출력하고 싶다면 switch (i%3) 구문을 사용하면 될 것이다.

 

: charani

#include <Turboc.h>

 

void main()

{

     int i;

 

     for (i=1;i<=75;i=i+1) {

          gotoxy(i,10);

          if (i%2 == 0) {

              puts(" __@");

          } else {

              puts(" ^^@");

          }

          delay(100);

     }

}

 

출력 문자열 앞쪽에 공백이 하나 더 있음을 유의하도록 하자. 이 공백은 이전의 달팽이 꼬리를 지우는 역할을 하는데 없을 경우 잔상이 남게 된다.

산술 연산자에 대해서는 다 알아보았고 산술 연산자와 모양이 똑같은 부호 연산자에 대해 알아보자. 부호 연산자는 피연산자의 부호를 바꾼다. score 변수에 23이라는 값이 들어 있다면 -score는 부호를 바꾸어 -23이 된다. 산술 연산자의 -와 부호 연산자의 -는 모양은 같지만 기능은 다르다. 뺄셈 연산자 -는 피연산자를 두 개 취하는 이항 연산자이고 부호 연산자 -는 피연산자 하나만 취하는 단항 연산자이다. 다음 식을 보자.

 

a*-b+c-d;

 

b앞의 -는 부호 연산자이고 d앞의 -는 산술 연산자이다. 어렵지 않게 구분될 것이다. 그럼 다음 대입문에서 -는 어떤 연산자일까?

 

a=-1;

 

여기서 사용된 -기호는 언뜻 보기에 부호 연산자인 것 같지만 사실은 연산자가 아니다. -1이라는 상수의 한 부분일 뿐이며 부호를 바꾸는 동작을 하지는 않는다. 부호 연산자 -를 사용하면 변수에 저장되어 있는 값의 음수값을 얻을 수 있다. 다음은 두 개의 정수형 변수 a와 b에 대한 연산예이다.

 

a+b         // a와 b를 더한다.

a+-b;       // a와 b의 음수값을 더한다.

a-b;        // a에서 b를 뺀다.

a--b;       // a에서 b의 음수값을 뺀다.

 

이 연산문중 앞쪽 세 개는 모두 합법적이다. 그러나 4번째 연산문은 에러로 처리되는데 왜냐하면 --는 감소 연산자라는 단항 연산자로 별도로 정의되어 있기 때문이다. 수학에서 --는 +와 같아지므로 a--b는 사실 a+b와 같지만 C에서는 그렇지 않다. 만약 정 이런 연산을 할 필요가 있다면 a- -b와 같이 공백을 하나 넣어 주든가 아니면 a-(-b)같이 괄호를 싸야 한다.

부호 연산자 +는 피연산자의 부호를 그대로 유지한다. 그래서 +a는 a와 같으며 수학에서 양수에 대해 특별한 표식을 붙이지 않듯이 C에서도 양수에 대해서는 +부호 연산자를 사용하지 않아도 된다. 하지만 다음 예처럼 일련의 변수 초기값을 수직으로 나란히 배치하고 싶을 때 음양에 상관없이 모양을 똑같이 작성하고 싶다면 이때 +부호 연산자가 약간의 도움이 된다.

 

int a = -1

int b = 2

int c = -5

int d = 6

int a = -1

int b = +2

int c = -5

int d = +6

 

이 연산자가 꼭 필요한 경우는 사실상 없으며 실제로 잘 사용되지도 않지만 음수 부호 연산자가 있으므로 대칭을 이루기 위해 양수 부호 연산자도 정의되어 있는 것이다. 변수의 부호 타입에도 부호없음을 뜻하는 unsigend가 있고 부호가 있음을 뜻하는 signed가 있는데 마찬가지로 대칭성을 위해 존재한다.

 

 ScrollChar

7칸마다 O를 출력하고 O의 사이에는 .을 출력해 보자. 나머지 연산자를 사용하면 "매 7칸마다"라는 조건식을 작성할 수 있다. 또한 루프를 구성하여 O문자가 1초에 다섯 번씩 오른쪽으로 움직이도록 하라. 반짝이며 이동하는 전구를 흉내낸다고 생각하면 된다.