본문 바로가기
Topos Uranos

요약

산술식은 읽는 순서대로 왼쪽에서 오른쪽으로 계산되지 않고, 숨은 구조인 식의 트리에 따라 계산된다. 이 트리를 정하는 것은 연산자의 우선순위와 결합 방향과 괄호이다. 그리고 이 트리의 각 노드에서 피연산자의 자료형이 어떤 연산을 할지 결정하므로, 7 / 2 식의 값은 3이고 7 / 2.0 식의 값은 3.5이다. 이 수업은 정수와 실수에 대한 C++의 다섯 산술 연산자, C++11부터 0 쪽으로 버리는 정수 나눗셈과 나머지(여기서 나머지가 피제수의 부호를 따르고, 피제수가 음수일 때 유클리드 나눗셈의 나머지와 다르다는 것이 따라 나온다), 유클리드 나머지를 얻는 방법, 식 트리, 피연산자의 자료형이 서로 다를 때 결과의 자료형, 그리고 정수 산술식이 의미를 잃는 두 가지 경우, 곧 0으로 나누는 것과 중간 계산에서 오버플로가 나는 것을 다룬다.

학습 목표

  1. C++에서 정수 나눗셈의 몫과 나머지를 음수 피연산자의 경우까지 포함하여 계산하고, 이를 유클리드 나눗셈의 몫과 나머지와 관련짓는다.
  2. 우선순위와 결합 방향에 따라 산술식의 트리를 그리고, 그 값을 계산한다.
  3. 자료형이 서로 다른 피연산자 사이의 연산에서 결과의 자료형을 예측한다.
  4. 정수 나눗셈과 나머지를 써서 양을 분해한다. 수의 각 자리, 시간과 분으로 나타낸 길이, 요일이 그 예이다.

산술 연산자

C++에는 이항 산술 연산자가 다섯 개 있다. 덧셈 +, 뺄셈 -, 곱셈 *, 나눗셈 /, 나머지 % 연산자이다. 그 밖에 유일한 피연산자의 부호를 바꾸는 단항 마이너스(-x 식처럼 쓴다)와, 피연산자를 그대로 두는 단항 플러스 +x 연산자가 있다. 처음 네 연산자는 정수와 실수에 모두 적용되고, 나머지 연산자는 정수에만 적용된다. 그런데 같은 표기가 언제나 같은 연산을 뜻하지는 않는다. / 연산자의 두 피연산자가 모두 정수이면 나눗셈은 정수 나눗셈이고 그 결과는 정수, 곧 소수 부분을 버린 몫이다. 어느 하나가 실수이면 나눗셈은 실수 나눗셈이다. 문자, 불리언, 형 변환, 상수 수업은 이 규칙의 가장 눈에 띄는 결과를 보여 주었다. double r{7 / 2}; 문장은 3을 저장한다. 결과가 실수로 변환되기 전에 나눗셈이 정수끼리 이루어졌기 때문이다.

예시두 정수에 대한 다섯 연산자

프로그램은 다섯 연산자를 17과 5에 적용하고, 실수 피제수로 나눗셈을 한 번 더 한다.

C++ 프로그램
#include <print>​int main(){    const int a{17};    const int b{5};    std::println("{} + {} = {}", a, b, a + b);    std::println("{} - {} = {}", a, b, a - b);    std::println("{} * {} = {}", a, b, a * b);    std::println("{} / {} = {}", a, b, a / b);    std::println("{} % {} = {}", a, b, a % b);    const double x{17.0};    std::println("{} / {} = {}", x, b, x / b);}
출력
17 + 5 = 2217 - 5 = 1217 * 5 = 8517 / 5 = 317 % 5 = 217 / 5 = 3.4

17을 5로 나누면 3이 되고 2가 남는다. 이것이 17개의 물건을 5개씩 묶을 때의 몫과 나머지이다. 마지막 줄은 실수를 정수로 나누어 3.4를 얻는다. 주의할 점은 std::println 함수가 실수 17.0을 “17”로 쓴다는 것이다. 빈 자리표시자는 값의 가장 짧은 표현을 쓰므로, 쓰인 것만으로는 자료형이 드러나지 않는다. 자료형을 보려면 {:.1f} 형식으로 소수 자리를 요구한다.

% 연산자는 실수를 받지 않는다. 7.5 % 2 식을 쓰는 것은 프로그램이 실행 중에 발견하는 논리 오류가 아니라 컴파일 오류이다. 컴파일러는 double 타입과 int 타입의 피연산자가 이 연산자에 쓸 수 없는 것이라고 알린다.

C++ 프로그램
#include <print>​int main(){    std::println("{}", 7.5 % 2);}
컴파일러 오류 메시지
main.cpp: In function ‘int main()’:main.cpp:5:28: error: invalid operands of types ‘double’ and ‘int’ to binary ‘operator%’    5 |     std::println("{}", 7.5 % 2);      |                        ~~~ ^ ~

실수 나눗셈의 나머지는 존재하며, <cmath> 헤더의 std::fmod 함수가 그것을 계산한다. 이 함수는 비트와 수학 라이브러리 수업에서 거듭제곱과 함께 공부한다. C++에는 거듭제곱 연산자가 없으며, 2 ^ 3 식의 값은 8이 아니라 다른 것인데, 그것도 거기서 설명한다.