요약
프로그램의 정수는 수학의 정수가 아니다. 그것은 비트의 유한한 나열이며, 비트에는 정확히 개의 서로 다른 값이 들어간다. 이 수업은 그 표현과 그 결과를 공부한다. 정수를 이진법과 십육진법으로 쓰고 그것을 형식 지정 {:b}, {:x}로 확인하는 법을 가르치고, C++의 정수 자료형과, sizeof 연산자로 재는 그 크기, std::numeric_limits로 알아보는 값의 범위를 소개한다. 음수가 2의 보수로 어떻게 표현되는지, 값의 범위가 왜 대칭이 아닌지 설명하고, 부호 있는 정수와 부호 없는 정수를 구별하며, 연산이 범위 밖으로 나갈 때 무슨 일이 일어나는지 살펴본다. 부호 없는 정수에서는 표준이 결과를 정하며, 그것은 법 산술이다. 부호 있는 정수에서는 표준이 결과를 정하지 않고, 프로그램은 모든 보장 밖에 놓인다. 마지막으로 각 데이터의 자료형을 고르는 기준을 제시한다.
학습 목표
- 정수를 십진법, 이진법, 십육진법 사이에서 변환하고, 그 변환을 형식 지정
{:b},{:x}로 확인한다. - 비트 정수의 값의 범위를 부호 있는 경우와 부호 없는 경우에 대해 계산하고,
std::numeric_limits와sizeof연산자로 확인한다. - 2의 보수를 설명하고, 작은 음수의 8비트 표현을 쓴다.
- 정의되지 않은 동작인 부호 있는 오버플로와, 법 산술인 부호 없는 오버플로를 구별하고, 후자의 결과를 예측한다.
- 데이터의 예상되는 값의 범위에 따라 알맞은 정수 자료형을 고르고, 너비가 중요할 때는
<cstdint>헤더의 고정 너비 자료형을 쓴다.
위치적 기수법
변수와 메모리 수업은 변수를 이름, 자료형, 값을 가진 칸으로 소개했다. 그런데 메모리는 십진 숫자를 저장하지 않는다. 메모리가 저장하는 것은 비트이며, 각 비트의 값은 0 또는 1이고, 여덟 비트씩 묶여 바이트를 이룬다(표준은 적어도 여덟 비트를 요구하며, 오늘날의 모든 시스템은 정확히 여덟 비트를 쓴다). 그러므로 정수 변수가 어떤 값을 가질 수 있는지 알려면, 숫자 두 개만으로 수를 어떻게 쓰는지 알아야 하며, 그것을 하는 것이 밑이 2인 위치적 기수법이다.
밑이 인 위치적 기수법에서 각 숫자의 값은 그 숫자가 차지한 위치에 따라 정해진다. 마지막 자리의 숫자는 에 곱해지고, 그 앞자리의 숫자는 에, 다시 그 앞자리의 숫자는 에 곱해지며, 이런 식으로 계속된다. 십진법에서 의 의미는 이다. 이진법에서 숫자는 0과 1이고, 가중치는 아래와 같은 2의 거듭제곱이다: 이로부터 이진법을 십진법으로 바꾸는 규칙이 나온다. 1이 있는 위치의 가중치를 더하면 된다.
그림은 8비트 패턴 00101101을 읽는다. 각 칸 위에는 그 칸의 가중치가 있다. 1들이 왼쪽에서 오른쪽으로 하나씩 켜지고, 값은 그 가중치들을 쌓아 간다.
증명
여덟 칸이 모두 꺼져 있다. 값은 0이다. 가중치는 오른쪽에서 왼쪽으로 아래와 같다: .
첫 번째 1은 가중치 32의 위치에 있다. 쌓인 값은 32이다.
이어지는 1은 가중치 8의 위치에 있다: .
그 뒤의 1은 가중치 4의 위치에 있다: .
마지막 1은 가중치 1의 위치에 있다: . 패턴
00101101은 수 45를 나타낸다.비트를 넷씩 묶으면 십육진법의 숫자가 된다.
0010은 2이고1101은 13인데, 13은 십육진법으로d로 쓴다. 그러므로 45는 십육진법으로2d로 쓴다.
반대 방향, 곧 십진법에서 이진법으로 가는 길은 연속 나눗셈으로 간다. 수를 2로 나누어 나머지(0 또는 1)를 적고, 몫으로 같은 일을 0이 될 때까지 되풀이한다. 나머지를 마지막 것부터 첫 번째 것까지 읽으면 그것이 이진법의 숫자이다. 45의 경우: , , , , , . 나머지를 거꾸로 읽으면 101101이 되고, 왼쪽에 0을 두 개 붙이면 그림의 패턴이 된다. 그 이유는 각 나머지가 나누어지는 수의 일의 자리 숫자이고, 각 몫이 그 수를 오른쪽으로 한 자리 민 것이기 때문이다. 같은 방법은 어느 밑에나 통한다. 밑 16에서는 16으로 나누고, 10부터 15까지의 나머지는 문자 a부터 f까지로 쓴다.
밑 16, 곧 십육진법은 편리함 때문에 쓰인다. 의 관계에 따라 십육진법의 각 자리는 정확히 4비트에 대응하고, 한 바이트는 두 자리로 쓰인다. 32비트의 수는 이진법으로는 서른두 자리를 차지해 읽기 어렵지만, 십육진법으로는 여덟 자리뿐이며, 계산 없이 한 자리씩 이진법으로 바꿀 수 있다. 그래서 프로그래머는 메모리를 십육진법으로 읽는다. 위치적 기수법의 수학적 기초는 강좌 「대수학과 기하학 I」의 수업 「위치적 기수법」에서 공부한다.
C++에서는 이 밑들로 직접 쓴 정수를 쓸 수 있다. 0b로 시작하는 리터럴은 이진법이고, 0x로 시작하는 리터럴은 십육진법이다. 어떤 리터럴 안에도 자릿수 구분자로 아포스트로피를 넣을 수 있는데, 컴파일러는 그것을 무시하고 읽는 사람은 그것을 반긴다: 0b0010'1101, 1'000'000. 출력에서 형식 지정 {:b}는 정수를 이진법으로 쓰고, {:x} 지정은 십육진법 소문자로, {:X} 지정은 대문자로 쓴다. 기호 #는 접두사를 앞에 붙이고, 앞에 0을 둔 너비는 왼쪽을 0으로 채운다.
#include <print>int main(){ const int decimal{45}; const int binary{0b0010'1101}; const int hexadecimal{0x2d}; std::println("{} {} {}", decimal, binary, hexadecimal); std::println("이진수: {:b}", decimal); std::println("8비트: {:08b}", decimal); std::println("십육진수: {:x} {:X} {:#x}", decimal, decimal, decimal);}45 45 45이진수: 1011018비트: 00101101십육진수: 2d 2D 0x2d세 변수는 같은 값을 세 가지 밑으로 써서 저장하며, 출력의 첫 줄이 그것을 보여 준다. 밑은 표기의 성질이지 수의 성질이 아니다. 메모리는 세 경우 모두 같은 비트 패턴을 저장한다. {:b} 지정은 왼쪽의 0을 생략하고, {:08b} 지정은 여덟 자리를 채운다.
콘텐츠를 불러오는 중…