[C/C++] 3. 실수형 자료형과 부동 소수점의 원리
앞서 정수형 자료형의 저장 구조와 2의 보수 표현 방식을 알아보았다. 이번 글에서는 소수점을 표현하는 실수형 자료형(float, double)의 내부 동작 원리인 부동 소수점(Floating Point) 체계와, 실수 연산 시 주의해야 할 정밀도 문제를 정리한다. 컴퓨터 메모리 관점에서 정수와 실수는 데이터를 저장하고 처리하는 방식이 완전히 다르다. - 정수형: 한정된 비트 공간 내에서 정확한 2진수 값으로 직관적으로 표현한다. - 실수형: $0$과 $1$ 사이에도 무한한 실수가 존재하기 때문에, 한정된 메모리 크기로 정확한 값을 담는 것은 불가능하다. 따라서 실수는 '정확한 값'이 아닌 '근사값'을 저장한다. 정수 와 실수 은 인간에게는 같은 수처럼 보이지만, 메모리에 저장되는 비트 패턴은 완전히 다르다. 컴퓨터는 IEEE 754 표준에 따라 실수를 지수부(Exponent)와 가수부(Mantissa)로 나누어 저장하는 부동 소수점 방식을 사용한다. $$\text{실수} = \text{가수부} \times 2^{\text{지수부}}$$ 1. 2진수 변환: $21.8125_{(10)} \rightarrow 10101.1101_{(2)}$ 2. 정규화(Normalization): 소수점을 이동시켜 맨 앞을 $1.\text{xxx}$ 형태로 맞춘다. - $1.01011101_{(2)} \times 2^4$ 3. 비트 분배: - 부호 비트 (Sign): 양수/음수 판별 - 지수부 (Exponent): 소수점의 위치 ($2^4$의 $4$) - 가수부 (Mantissa): 소수점 뒤의 유효 숫자 영역 () 소수점 아래 자릿수가 길어질수록 가수부 비트 공간이 부족해진다. 따라서 더 큰 메모리를 사용하는 자료형일수록 더 높은 를 가진다. |자료형|메모리 크기|유효 자릿수 (정밀도)|비트 구성 (부호 / 지수 / 가수)| |---|---|---|---| |float|4 바이트 (32 비트)|소수점 이하 약 7자리|$1 \text{ bit} / 8 \text{ bits} / 23 \text{ bits}$| |double|8 바이트 (64 비트)|소수점 이하 약 15~16자리|$1 \text{ bit} / 11 \text{ bits} / 52 \text{ bits}$| > C/C++에서는 기본 실수 리터럴(예: )을 형으로 처리한다. 형으로 명시하려면 숫자 뒤에 리터럴 접미사를 붙여야 한다 (). 부동 소수점 방식의 핵심은 "모든 실수를 정확하게 표현할 수 없다"는 점이다. 실수 연산 시 미세한 오차가 발생하므로, 조건문에서 연산자로 실수를 직접 비교하면 예상치 못한 버그가 발생한다. 정수와 실수가 혼합된 연산을 수행하면 컴퓨터는 둘 중 하나의 체계로 변환하는 암시적 형변환(Implicit Casting)을 거치게 되며, 이 과정에서 성능 하락이나 값 유실이 발생할 수 있다. 따라서 의도하지 않은 연산 오류를 방지하기 위해 가능하면 같은 자료형끼리 연산하고, 정수와 실수를 함께 사용할 때에는 명시적 형변환을 통해 개발자의 의도를 컴파일러에게 확실히 전달해야 한다. - 정수는 '정확한 값', 실수는 '근사값'으로 처리된다. - 실수 비교 시 연산 대신 오차 범위()를 고려하여 비교해야 한다. - 혼합 연산 시 소수점 절삭 등의 오차를 막기 위해 명시적 형변환을 적극 활용하자.
[C/C++] 2. 정수형 자료형과 2의 보수
앞서 변수와 메모리의 기초 단위(Bit, Byte)를 알아보았다. 이번 글에서는 정수형 자료형이 데이터를 표현하는 두 가지 방식인 부호 있는 정수(Signed) 와 부호 없는 정수(Unsigned), 그리고 컴퓨터가 음수를 처리하는 원리인 2의 보수(2's Complement)를 정리한다. 1바이트(8비트)는 총 $2^8 = 256$가지의 상태를 표현할 수 있다. 이 256가지의 상태를 어떻게 해석하느냐에 따라 표현 범위가 완전히 달라진다. - Unsigned (부호 없음): 256가지 상태를 오직 0과 양수에만 배정한다. (범위: $0 \sim 255$) - Signed (부호 있음): 256가지 상태를 음수와 양수에 절반씩 나누어 배정한다. (범위: $-128 \sim 127$) 자료형에서는 8개의 비트 중 가장 왼쪽에 위치한 비트를 MSB(Most Significant Bit, 최상위 비트)라고 부른다. - MSB가 인 경우: 양수로 해석한다. - MSB가 인 경우: 음수로 해석한다. 즉, MSB는 해당 숫자가 양수인지 음수인지 판별하는 '부호 비트'의 역할을 수행한다. 컴퓨터는 뺄셈을 전용으로 처리하는 회로를 따로 두지 않고, "음수의 덧셈"으로 처리하여 연산 속도를 최적화한다. 그렇다면 컴퓨터는 음수를 어떻게 정의할까? > 음수의 정의: 어떤 양수 $A$와 더했을 때 $0$이 되는 수 8비트 공간에서 ()과 더해서 을 만들 수 있는 비트 패턴은 모든 비트가 로 채워진 이다. Plaintext 따라서 은 Signed 기준 을 의미한다. 어떤 양수에 대응하는 음수 비트를 찾는 방법은 매우 간단하다. 1. 모든 비트를 반전시킨다. ( -> , -> ) 2. 결과에 을 더한다. 동일한 메모리 공간에 동일한 비트()가 저장되어 있어도, 개발자가 선언한 자료형에 따라 컴퓨터가 해석하는 값이 달라진다. - 로 해석 시: - 로 해석 시: 비트 데이터 자체는 동일하지만, 자료형이라는 '설명서'에 따라 전혀 다른 값으로 읽히는 것이다. 비트 수가 늘어날수록 표현 가능한 수의 범위는 기하급수적으로 증가한다. | 자료형 | 크기 | Unsigned 표현 범위 | Signed 표현 범위 | | --------- | ------------- | ----------------------------- | ------------------------------------------------- | | char | 1 바이트 (8 비트) | $0 \sim 255$ | $-128 \sim 127$ | | short | 2 바이트 (16 비트) | $0 \sim 65,535$ | $-32,768 \sim 32,767$ | | int | 4 바이트 (32 비트) | $0 \sim \text{약 } 42\text{억}$ | $\text{약 } -21\text{억} \sim \text{약 } 21\text{억}$ | > 💡 게임 개발 시 자료형 선택이 중요한 이유 > >고전 게임에서 캐릭터 스탯이나 아이템 최대 수량이 255로 제한되어 있던 이유는 1바이트() 자료형을 사용했기 때문이다. > >만약 현대 게임에서 몬스터의 HP를 로 설정해 두었는데, 파워 인플레이션으로 인해 HP가 21억을 넘어서는 순간 오버플로우가 발생하여 HP가 음수()로 변해버리는 치명적인 버그가 발생할 수 있다. 따라서 담고자 하는 데이터의 최댓값을 고려하여 적절한 크기(, 등)와 부호 키워드()를 선택하는 것이 중요하다. --- 동일한 이진수 데이터라도 어떤 자료형으로 바라보느냐에 따라 전혀 다른 의미를 가진다. 자료형의 한계 범위를 명확히 인지하고 코드를 작성하는 습관을 들이도록 하자.
[C/C++] 1. 변수와 자료형
프로그래밍을 처음 시작할 때 가장 먼저 마주하게 되는 개념인 자료형(Data Type)과 변수(Variable), 그리고 그 밑바탕이 되는 메모리 단위를 정리한다. 코드를 작성할 때 사용하는 와 같은 구문은 각자 명확한 역할을 수행한다. - 자료형(): 변수가 어떤 형태의 데이터를 저장할지, 메모리에서 어느 정도의 크기를 차지할지를 결정하는 설명서역할을 한다. - 변수(): 데이터를 저장하는 실제 메모리 공간에 붙이는 이름표다. 개발자가 직접 이름을 정할 수 있다. 자료형은 크게 정수형과 실수형으로 나뉘며, 어떤 자료형을 선택하느냐에 따라 컴퓨터가 데이터를 처리하는 방식과 메모리 점유 크기가 결정된다. 프로그래밍에서 메모리 크기를 말할 때 사용하는 단위인 '바이트(Byte)'에 대한 개념을 잡는 것이 중요하다. - 비트(Bit): 컴퓨터가 정보를 처리하는 최소 단위로, 또는 의 두 가지 상태만 가질 수 있다. - 바이트(Byte): 8개의 비트가 모여 1바이트가 된다. - 데이터 크기: 대표적인 정수형인 형은 4바이트(32비트) 크기를 가지며, 이를 통해 정수 데이터를 효율적으로 저장한다. 자료형은 단순히 데이터를 담는 그릇이 아니라 데이터를 표현하는 방식과 범위를 정의한다. 특히 1바이트 크기의 자료형을 보면 이해가 쉽다. - 경우의 수: 1바이트(8비트)는 $2^8 = 256$가지의 상태를 표현할 수 있다. - unsigned 키워드: 는 말 그대로 부호(sign)가 없다는 뜻이다. 음수를 표현하지 않는 대신, 모든 비트를 양수를 나타내는 데 사용하여 표현 범위를 2배 넓혀준다 (0~255). 변수가 수용할 수 있는 범위를 넘어서는 데이터를 넣으면 오버플로우(Overflow) 라는 현상이 발생하여 예상치 못한 결과가 나온다. > 💡 쉽게 이해하기 > 손으로 누르는 3자리 수동 카운터(클리커) 가 999에서 버튼을 한 번 더 누르면 000으로 리셋되는 것과 같다. 1바이트(8비트) 공간에 256을 넣으려 하면, 8비트를 넘어선 상위 비트 정보는 사라지고 남은 비트 값()만 남게 된다. 컴퓨터 언어는 명시한 자료형의 규칙을 엄격하게 따르기 때문에, 개발자는 변수를 선언할 때 저장할 데이터의 범위를 항상 고려해야 한다. --- , 같은 자료형은 컴퓨터가 데이터를 체계적으로 관리하기 위한 약속이다. 코드 한 줄을 짤 때마다 이 변수는 몇 바이트이고, 어떤 데이터를 담을 것인가를 고민하는 습관을 들인다면, 코딩 실력은 한층 더 견고해질 것이다.