목차
정말 실수를 많이 유발하는 실수
실수(mistake)가 아니라 실수(real number)에 대한 글.
이 실수는 정말 계산하기가 화가 난다.
밑의 예를 보자.
void check_real(int n){
double answer = n*(1.0/n);
if(answer != 1)
printf("not the same number!!\n");
}
int main(){
for(int i = 1; i < 100; i++)
check_real(i);
}
간단한 x * (1 / x)가 1인지에 대한 함수이다.
수학적으로 당연히 저 printf문은 실행되서는 안된다.
하지만 이 코드를 실행시키면, 어째서인지 한 두개의 printf문이 실행된다.
이런 경우 때문에 실수(real number) 연산은 예외를 적용시켜줘야 한다.
예외 때문에, 자잘한 실수(mistake)가 발생할 가능성이 커지고, 점점 화가난다.
왜 이런 경우가..
실수는 무한 값을 가지는 경우가 있다.
친구 3명이랑 음식점을 가서 10만원이 나왔다. 그럼 33333.33333... 원을 내야하고,
원의 넓이를 계산할 때, 무한소수인 π를 쓰고,
자연로그의 밑으로 e를 쓰는 등의 무한한 값을 가진다.
그에 반해, 컴퓨터의 메모리는 유한하다.
초등학교 원의 넓이를 구할 때, 3.141592... 를 3.14라는 근사 값을 사용해서 구했듯이,
컴퓨터도 실수를 근사 값을 사용해서 저장하고, 계산한다.
컴퓨터의 실수 표기
우리의 종만북..에서는 IEEE 754를 간단히 소개한다.
- 이진수로 실수를 표기하는 법
- 부동소수점 표기법.
浮動으로 뜰 부(浮)를 쓴다. 不動 아니 부(不)가 아니다.
- 무한대값, 비정규수, NaN(Not a Number)등의 존재
이진법 표기의 실수.
십진법으로 실수를 표기해보자.
0.1 => 1/10
0.01 => 1/100
이런식으로 하나하나 소수점이 내려갈 때마다, 1/10씩 곱해진다.
그럼 이진법으로 생각을 해보자.
0.1 => 1/2(0.5)
0.01 => 1/4(0.25)
이런식으로 소수점이 하나씩 내려갈 때마다, 1/2씩 곱해진다.
그럼 한번 예를 들어서
11001.1011는 십진법으로 고치면 어떻게 될까.
정수 부분은
2^4*1 + 2^3*1 + 2^2*0 + 2^1*0 + 2^0*1 = 25
소수 부분은
2^(-1)*1 + 2^(-2)*0 + 2^(-3)*1 + 2^(-4)*1 = 0.6875
로
25.6875가 된다.
부동 소수점
그럼 실수를 컴퓨터에 넣어보자.
32비트 자료형에, 64비트 자료형에 실수를 넣으면
정수부분과, 실수부분을 어떻게 나눠야 할까?
간단하게 어떤 지점을 딱 정해놓는다고 생각을하자.
예를들어, 32비트 자료형에서는
정수부분 10비트, 소수부분 22비트 이런식으로 말이다.
이렇게 되면
누구는 정수부분을 많이 쓰고 싶을 수 있고,
누구는 소수부분을 많이 쓰고 싶을 수 있다.
모두가 만족하는 방법으로 정수, 실수를 나눌 수가 없다.
그래서 IEEE 754는 두 부분을 나누지 않고,
소수점을 없앤 수를 저장한 후 따로 소수점을 몇칸 옮겼는지를 저장한다.
아까 예를 들었던 11001.1011을 들고와보자.
일단, 제일 첫번째수가 정수부분의 유일한 자리가 되도록 소수점을 옮긴다.
1.10011011
그리고, 소수점을 왼쪽으로 몇 번 옮겼는지를 기록한다.
이 경우에는 왼쪽으로 4번 옮겼다.
그럼 실수의 부동소수점 표기는 다음과 같은 정보를 포함한다. - 부호 : 양수, 음수를 판단하는 비트 - 지수 : 소수점을 옮긴 칸 수를 나타내는 비트 (4칸) - 가수 : 소수점을 지수 만큼 옮긴 수(1.10011011)
여기서 또, 비트를 몇 비트씩 주는지가 고민이다.
부호비트는 당연히 1비트일 것이고, 나머지 지수와 가수를 몇 비트씩 줘야할까?
지수에 많은 비트를 할당한다고 하자.
64비트 자료형을 기준으로 53비트정도를 지수에 할당했다.
그럼 총 소수점을 2^52만큼(양수와 음수 포함해서) 즉, 4503599627370496자리만큼 옮길 수 있다.
하지만 가수부분은 고작 10비트로 굉장히 많이 잘려나가서,
너무 정확하지 않아 사용하기가 힘들 정도다.
반대로 지수비트를 10비트, 가수비트를 53비트 할당하면.
총 옮길수 있는 소수점은 1024자리, 가수부분은 53비트로 꽤나 정확한 근사값을 표현 할 수 있다.
그럼에도 실수는 계산이 쌓이다보면, 언젠가 오차가 나게 된다.
64비트 실수는 그래도 많은 수의 가수(십진수로 15자리 즈음)가 있어 근사값이 꽤나 정확한데 비해,
32비트 실수는 비교적 적은 수의 가수비트(십진수로 6자리 즈음)가 있다.
제일 좋은건 실수를 쓰지 않는 것이지만, 어쩔 수 없을 때에는 64비트이상의 자료형을 쓰자.
이렇게 실수를 표현하는 방법을 _부동소수점_이라고 한다.
실수 너무 싫어.
저렇게 좋은 실수 표기법이지만 계산이 쌓이면, 결국 오차가 발생한다.
다음 포스트에서는 그 오차를 어떻게 잡아낼지에 대해서 알아보도록 하자.
'Algorithm' 카테고리의 다른 글
에라토스테네스의 체(2022.04.13) (0) | 2022.08.03 |
---|---|
산술 오버플로(2021.06.21) (0) | 2022.08.03 |
자주 하는 실수들(2021.06.17) (0) | 2022.08.03 |
코딩의 중요성(2021.06.16) (0) | 2022.08.03 |
문제 해결 전략(2021.06.13) (0) | 2022.08.03 |