![[CS50] C언어 - 하드웨어의 한계](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbG5p1D%2FbtsHVqwksQR%2F2sQKfrzXJeRqwjgodOdluK%2Fimg.jpg)
컴퓨터의 메모리와 데이터 처리
컴퓨터는 RAM(랜덤 액세스 메모리)이라는 물리적 저장장치를 포함하고 있다.
우리가 작성한 프로그램은 실행 중에 RAM에 저장된다.
RAM은 유한한 크기의 비트만 저장할 수 있기 때문에 때때로 부정확한 결과를 낼 수 있다.
부동 소수점 부정확성
아래와 같이 실수 x
, y
를 인자로 받아 x
나누기 y
를 하는 프로그램이 있다고 해보자.
#include <cs50.h>
#include <stdio.h>
int main(void)
{
float x = get_float("x: ");
float y = get_float("y: ");
printf("x / y = %.50f\n", x / y);
}
나눈 결과를 소수점 50자리까지 출력하기로 하고, x
에 1을, y
에 10을 입력하면 아래와 같이 결과가 나온다.
x: 1
y: 10
x / y = 0.10000000149011611938476562500000000000000000000000
정확한 결과는 0.1이 되어야 하지만, float
에서 저장 가능한 비트 수가 유한하기 때문에 다소 부정확한 결과를 내게 된다.
부동 소수점 수는 컴퓨터에서 실수를 표현하는 방식이다.
C언어에서는 float
와 double
데이터 타입으로 사용된다.
float
는 총 32비트로 구성되고 각 비트는 세 가지 부분으로 나뉜다.
- 부호부$_{Sign \space bit}$: 1비트 (보라색)
- 지수부$_{Exponent}$: 8비트 (노란색)
- 가수부$_{Fraction, \space Mantissa}$: 23비트 (초록색)
부호부
부호부는 숫자의 부호를 나타낸다. 0은 양수, 1은 음수를 의미한다.
지수부
지수부는 숫자의 크기를 나타내는 역할을 한다. 지수의 부호를 포함하기 위해 바이어스(bias)라는 값을 사용한다.
float
의 경우, 바이어스 값은 127이다.
예를 들어 저장된 지수 값이 130이라면 실제 지수는 130 - 127 = 3이 된다.
가수부
가수부는 실제 수의 유효 자릿수를 저장한다.
가수부는 1보다 크거나 같은 숫자를 표현하기 위해 정규화(normalization)된 형태로 저장된다.
부동 소수점 표현에서 가수는 항상 1비트 형태로 가정되므로, 실제 저장되는 값은 소수점 이하의 부분만 저장된다.
부동 소수점 수가 정확한 값을 저장하지 못하는 이유가 바로 이 가수부의 비트 수가 제한적이기 때문이다.
가수부가 저장할 수 있는 비트 수가 제한적이기 때문에 아주 작은 소수나 매우 큰 소수를 표현할 때 정확도가 떨어진다.
더 많은 비트를 사용해서 가수부를 확장하는 방법이 바로 double
이다.
더 정확한 값을 저장할 수 있지만 저장 공간을 비교적 많이 차지하기 때문에 효율성과 트레이드오프 관계에 있다.
float
대신 double
을 사용하면 가수부가 52비트로 늘어나 더 정확한 값을 저장할 수 있지만 여전히 한계는 존재한다.
정수 오버플로우
비슷한 오류로 1부터 시작해 2를 계속 곱하면서 출력하는 아래와 같은 프로그램이 있다고 해보자.
#include <stdio.h>
#include <unistd.h>
int main(void)
{
for (int i = 1; ; i *= 2)
{
printf("%i\n", i);
sleep(1);
}
}
이 프로그램에서 변수 i
를 int
타입으로 저장하기 때문에 2를 계속 곱하다가 int
타입이 저장할 수 있는 최대값을 넘으면 아래와 같은 오류와 함께 0이 출력될 것이다.
...
1073741824
overflow.c:6:25: runtime error: signed integer overflow: 1073741824 * 2 cannot be represented in type 'int'
-2147483648
0
0
...
정수를 계속 키우는 프로그램에서 21억을 넘기자 오버플로우가 발생한 것이다.
int
타입이 32비트로 표현할 수 있는 수의 한계를 넘었기 때문이다.
유명한 오버플로우 문제
Y2K 문제
- 1999년에 큰 이슈가 되었던 Y2K 문제는 연도를 마지막 두 자리수로 저장했던 관습 때문에 새해가 오면 ‘99’에서 ‘00’으로 정수 오버플로우가 발생하고 새해가 2000년이 아닌 1900년으로 인식될 수 있다는 문제
- 전 세계에서 수백만 달러를 투자해 프로그래머들에게 더 많은 메모리를 활용해 이를 해결하도록 함
보잉 787 문제
- 비행기 보잉 787에서는 구동 후 248일이 지나면 모든 전력을 잃는 문제가 있었음
- 소프트웨어의 변수가 248일이 지난 뒤에 오버플로우되어 발생 (248일을 1/100초 단위로 계산하면 약 2의 32제곱이 되기 때문)
- 보잉을 설계할 때 사용한 변수보다 너무 큰 값이 되어버려 주기적으로 재가동하여 변수를 다시 0으로 리셋
위와 같은 예시를 통해 다루고자 하는 데이터 값의 범위를 유의하면서 프로그램을 작성하는 것이 중요하다는 것을 개발자들은 느끼게 되었다.
데이터 타입과 변수의 한계를 이해하고 코드를 작성해야 부정확성이나 오버플로우로 인한 오류를 방지할 수 있다.
references
https://www.boostcourse.org/cs112/lecture/119010?isDesc=false
모두를 위한 컴퓨터 과학 (CS50 2019)
부스트코스 무료 강의
www.boostcourse.org
https://www.youtube.com/watch?v=-GsrYvZoAdA&ab_channel=%EC%BD%94%EB%94%A9%EC%95%A0%ED%94%8C
'CSE > CS 기초' 카테고리의 다른 글
[CS50] 배열 - 디버깅 (0) | 2024.06.13 |
---|---|
[CS50] 배열 - 컴파일링 (1) | 2024.06.12 |
[CS50] C언어 - 사용자 정의 함수, 중첩 루프 (0) | 2024.06.12 |
[CS50] C언어 - 자료형, 형식 지정자, 연산자 (1) | 2024.06.12 |
[CS50] C언어 - 문자열 (1) | 2024.06.12 |
컴퓨터 전공 관련, 프론트엔드 개발 지식들을 공유합니다. React, Javascript를 다룰 줄 알며 요즘에는 Typescript에도 관심이 생겨 공부하고 있습니다. 서로 소통하면서 프로젝트 하는 것을 즐기며 많은 대외활동으로 개발 능력과 소프트 스킬을 다듬어나가고 있습니다.
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!