공부하는 스누피

[컴퓨터구조] 부동소수점 본문

CS/컴퓨터구조

[컴퓨터구조] 부동소수점

커피맛스누피 2020. 11. 10. 17:18

과학적 표기법(scientific notation)

소수점의 왼쪽에 한 자릿수만을 갖도록 한 표기법

정규화된 수(normalized number)

과학적 표기법으로 표현된 숫자 중에서 맨 앞에 0이 나오지 않도록 한 수

 

부동소수점

이진수를 정규화된 형태로 표현하기 위해서는 기수(base)가 필요한데, 이를 이진 소수점(binary point)이라고 한다.

이런 수를 지원하는 컴퓨터 연산이 부동소수점(floating point) 연산이다. 부동(floating)은 소수점이 고정되어 있지 않다는 의미다. C언어에서는 이러한 수를 나타내기 위해 float라는 변수명을 사용한다.

 

이진 소수점으로 나타낸 실수는 다음과 같다.

1.xxxxxxx * 2^yyyy

컴퓨터에서는 y에 해당하는 지수도 이진법을 사용하여 나타낸다.

 

부동소수점의 장점

- 부동소수점 숫자를 포함한 자료의 교환을 간단하게 한다.

- 숫자가 항상 정규화된 형태로 표현되어 산술 연산이 간단해진다.

- 불필요하게 선행되는 0을 저장하지 않아도 되기 때문에 한 워드 내에 저장할 수 있는 수의 정밀도를 증가시킨다.

(ex. 0.000101보다 1.01 * 2^3이 더 효율적이다)

 

부동소수점의 표현

고정된 워드 크기를 사용하므로 소수부분(fraction, mentissa)의 크기와 지수(exponent)의 크기 사이에서 타협점을 찾아야 한다. 소수부분의 크기를 증가시키면 수의 정밀도가 높아지고, 지수의 크기를 증가시키면 수의 표현 범위가 늘어난다. 

(-1)^S * F * 2^E

S: 부동소수점 수의 부호

F: 소수부분

E: 지수

 

계산된 지수가 너무 커서 지수 필드에 표현될 수 없을 만큼 클 때 오버플로(overflow)가 발생한다. 

음의 값을 갖는 지수의 절댓값이 너무 커서 지수 부분에 표현될 수 없을 경우 언더플로(underflow)가 발생한다.

 

언더플로와 오버플로의 발생을 줄이는 방법으로 지수 부분을 크게 하는 2배 정밀도(double precision) 부동소수점 연산이 있다. C언어에서는 이를 double이라고 한다. 기존 32bit로 표현한 방식은 단일 정밀도(single precision) 부동소수점이라고 한다. 

 

오버플로와 언더플로가 발생한 것을 사용자에게 알리기 위해 예외(or 인터럽트)를 발생시킨다. 예외와 인터럽트는 예정되지 않은 프로시저 호출이다. 오버플로/언더플로가 발생된 명령어의 주소는 레지스터에 저장되고, 예외에 적합한 루틴으로 점프한다. 예외 루틴이 끝난 뒤 다시 돌아와 프로그램을 정상적으로 동작하게 한다.

 

바이어스된 표현법(biased notation)

IEEE 754 부동소수점 표준은 정규화된 이진수의 가장 앞쪽 1비트를 생략하고 표현하지 않는다. 정렬을 쉽게 하기 위해 부호 비트를 최상위 비트에 위치시켰다. 하지만 음수 지수는 숫자 정렬을 어렵게 만들어 지수를 바이어스된 표현법으로 표기하는 것이 이상적이다.

가장 음수인 지수를 00....00으로, 가장 양수인 지수를 11...11로 표현하는 방법을 바이어스된 표현법이라고 한다. 바이어스는 실제값을 구하기 위해 부호없이 표현된 수에서 빼야 하는 상수를 말한다.

IEEE 754는 단일 정밀도 펴현방식에서는 바이어스값 127을 사용한다. 따라서 -1은 -1 + 127 또는 126 = 01111110으로 표현된다. 2배 정밀도의 바이어스는 1023이다. 

<기본 공식>
(-1)^S * (1+소수) * 2^(지수-바이어스)
(예제) 십진수를 이진수로
-0.75
= -3/4
= -11/100 (이진수로)
= -0.11
= -0.11 * 2^0 (과학적 표기법)
= -1.1 * 2^-1 (정규화)
= (-1)^1 * 0.1 * 2^(126 - 127) (단일 정밀도 표현)
=> (-1)^1 * (1 + .1000 0000 0000 0000 0000 0000) * 2^(126-127)
= (-1)^1 * 0.1 * 2^(1022 - 1023) (2배 정밀도 표현)
(예제) 이진 부동소수점 수를 십진 부동소수점 수로 변환
1100000010100000000000000000000
=>
significant bit: 1
지수 부분: 10000001
소수부분 0100000000000000000000
=>
부호 비트 1, 지수 부분 129, 소수부분 1/4 = 0.25
(-1)^1 * (1+0.25) *2^(129-127) = -1 * 1.25 * 4 = -5.0

 

부동소수점 덧셈

1) 두 수의 지수를 비교한다. 작은 쪽의 지수가 큰 쪽의 지수와 같아질때까지 작은 수를 오른쪽으로 시프트한다.

2) 유효자리를 서로 더한다.

3) 정규화된 과학적 표기법으로 정돈한다. (오버플로와 언더플로를 검사한다)

4) 부호를 제외한 유효자리의 길이에 맞게 자리맞춤(round)을 해준다. (반올림해준다)

(예제)
0.5 + -0.4375
0) 두 수를 정규화된 이진 표기법으로 정돈한다.
0.5 = 1.000 * 2^-1
-0.4375 = -7/16 = -111/10000
           = -0.0111 * 2^0 = -1.110 * 2^-2
1) -1.110*2^-2의 지수가 작으니 오른쪽으로 시프트해준다.
-1.110*2^-2 = -0.111 * 2^-1
2) 유효자리를 더한다.
1.000 * 2^-1 + -0.111 * 2^-1 = (1.000 - 0.111) * 2^-1
                                       = 0.001 * 2^-1
3) 정규화된 과학적 표기법으로 정돈한다.
0.001 * 2^-1 = 1.000 * 2^-4
4) 결과를 자리맞춤한다.
이미 4bit 정밀도와 일치하므로 round할 필요가 없다.
1.000 * 2^-4 = 0.0001000 = 0.0001 = 1/2^4 = 1/16

 

부동소수점 곱셈

1) 두 수의 바이어스된 지수를 더한 값에 바이어스를 빼서 곱의 지수를 구한다. (=바이어스 없이 지수를 더한다)

2) 유효자리를 서로 곱한다.

3) 정규화된 형태로 정돈한다. (오버플로와 언더플로를 검사한다)

4) 부호를 제외한 유효자리의 길이에 맞게 자리맞춤을 해준다.

5) 부호가 같으면 결과의 부호는 양수이고 그렇지 않으면 음수이다.

(예제)
0.5 * -0.4375
0) 두 수를 이진 표기법으로 만든다.
0.5 = 1.000 * 2^-1
-0.4375 = -7/16 = -111/10000 
           = -0.0111 * 2^0 = -1.110 * 2^-2
1) 바이어스 없이 지수를 더한다.
-1 + (-2) = -3
2) 유효자리를 곱한다.
 1.000
*1.110
-------
   0000
  1000
 1000
1000
1110000
= 1.110 * 2^-3
3) 정규화한다.
이미 정규화되어 있고, 지수가 [-126, 127]에 포함된다.
4) 자리맞춤한다.
이미 자리맞춤 되어있다.
5) 피연산자들의 부호가 다르므로 곱의 부호를 음수로 한다.
-1.110 * 2^-3
= -0.001110 = -0.00111 = -7/32

+ 소수 십진수를 이진수로 표현하는 방법

소수부분을 2로 계속 곱해준다.

처음 곱했을 때 나왔던 소수부분이 다시 나오면 종료한다. (무한으로 반복되는것을 의미)

(예시)

0.25 => 0.25*2 = 0.5, 0.5*2 = 1.0 => 0.01

0.3 => 0.3*2 = 0.6, 0.6*2 = 1.2, 0.2*2 = 0.4, 0.4*2 = 0.8, 0.8*2 = 1.6 => 0.6이 처음 나왔던 소수 부분이니까 종료.

     => 0.01001

 

+ 소수 이진수를 십진수로 표현하는 방법

소수 십진수를 이진수로 표현하는 방법을 거꾸로 사용한다.

소수부분의 끝부터 하나씩 읽는다. 처음 소수부분이 1일 경우 x * 2= 1을 만족하는 x가 1/2이다.

그 다음 소수부분도 1일 경우 x * 2 = 1+1/2를 만족하는 x를 구한다. 이때 x는 3/4가 된다.

다음 소수부분이 0일 경우 x * 2 = 3/4를 만족하는 x를 구한다. 이때는 식의 결과부분에 1을 더해주지 않는다. 

1) 소수부분의 끝부터 하나씩 읽는다. 소수부분의 끝은 항상 1이므로 0.5부터 시작한다.
2) 다음 소수부분이 1일 경우 이전 결과값에서 1을 더한값과 동일한 x*2 식의 x를 구한다.
3) 다음 소수부분이 0일 경우 이전 결과값과 같은 x*2식의 x를 구한다.

(예시)

0.00111

1 => 1/2

1 => x*2 = 3/2 => x = 3/4

1 => x*2 = 7/4 => x = 7/8

0 => x*2 = 7/8 => x = 7/16

0 => x*2 = 7/16 => x = 7/32

 

 

 

(참고)

David A. Patterson, John L. Hennessy (2018). Computer Organization and Design (ARM Edition)

m.blog.naver.com/PostView.nhn?blogId=juyoung_g&logNo=220531788284&proxyReferer=https:%2F%2Fwww.google.com%2F

 

#1. 십진수 소수점을 이진수로 변환

보통 십진수를 이진수로 바꿀 때, 그 수를 2로 나눈 다음의 나머지를 차례로 배열해서 구할 수 있다.그러면...

blog.naver.com

 

Comments