Post

컴구(2)

arithmetic for computers

컴퓨터에서 어떻게 수학적 연산을 처리하는지를 알아보겠습니다.

개요

덧셈은 carry를 사용해서, 뺄셈은 2의 보수(2’s complement), 곱셈은 덧셈을 여러 번 하는 형식으로,

addition

모든 숫자를 컴퓨터는 이진수로 인식합니다. 0+0, 1+0, 0+1을 하면 문제가 딱히 없지만 1+1을 하는 순간 2가 아닌 0으로 인식해야 합니다. 이후 올림을 해줘야하는데, 이를 carry라고 합니다.

##

https://hi-guten-tag.tistory.com/253

floating point

컴퓨터로 정수를 계산하는 방법은 알았는데, 소수부가 있는 수는 어떻게 계산하는지에 대해 의문이 생깁니다. 이제 그 방법을 알아보도록 하겠습니다.

부동소수점

컴퓨터는 이진수를 사용해서 정수를 나타냅니다. 0.5는 어떻게 표현하나요? 이진수를 사용해서 0.1(2)로 표현할 수 있습니다. 왜냐하면 이진수를 두 배 키우고 싶으면 left shifting을 1칸 하기 때문입니다. 그렇다면 0.5, 즉 1의 0.5배인 0.5는 1칸 right shifting하면 되기 때문입니다.

하지만 0.3164515454215212154547854121…..같은 숫자는 어떻게 표현하나요? 확실히 모르겠습니다. 이처럼, 애매한 숫자들은 컴퓨터가 나타내기 힘듭니다. 컴퓨터는 몇 개의 비트를 사용해서 숫자를 표현하는데, 이 비트를 다 써버릴만큼의 복잡한 숫자는 표현하지 못하는 문제가 생깁니다. 즉, 숫자를 표현하는데 제한이 있습니다. 최대한 비슷하도록 근사를 하자는 것이 목적입니다. 목적 달성을 위해 부동소수점(floating point)이라는 개념이 도입됩니다. floating의 뜻은 떠다닌다는 의미지 않나요? 즉 소수점이 일정하게 표현되지 않고, 값에 따라 다르게, 물에 떠다니는 것 처럼 표현한다고 해서 부동소수점입니다.

일단 부동소수점을 어떻게 표현하는지부터 이해해봅시다. 그래야 계산을 할 수 있을테니!

IEEE 754

보통 소수를 real world에서 표현하면

1
2
3
2.5(가수부)*10^3(지수부) ... 
7.1*10^2 ..
a(1<=a<10) *10^b(b는 정수)..

형태로 표현합니다. 컴퓨터도 비슷한 형태로 표현하는데, 10진수 체계가 아닌 2진수 체계이므로

1
+-a(1.0<=a<2.0) * 2^b..

로 표현합니다. 이를 표현하기 위해서 IEEE 754라는 표준 규격을 사용합니다. IEEE 754 부동 소수점은 세 가지 부분으로 구분되는데, 부호/지수/가수 부분으로 구분됩니다. 위와 비슷합니다.

image

1
x=(−1)^(sign) × (1+fraction)×2^((exponent−bias)), exp는 000000000..000 과 11111...111은 안됨!

출처 : 위키피디아 부동소수점

지수 부분을 exp, 가수 부분을 fraction/mantissa라고 부릅니다. 실수를 32bit로 표현한다면, exp 부분을 8bit, fraction 부분을 23bit 사용합니다. 또한 bias로 127을 사용합니다. 64bit로 표현한다면, exp 부분을 11bit, fraction 부분을 52bit로 표현합니다. 또한 bias로 1203을 사용합니다. sign 부분이 1이라면 음수, 0이라면 양수로 나타냅니다.

예시로 -5.0을 나타내보겠습니다. 32bit를 사용해서 실수를 나타낸다고 가정해보겠습니다.

-5.0은 = -1 * 1.01(2) (=1.25) * 2^2 입니다. bias는 127이므로 exp는 129 -> 10000001(2)가 됩니다. 또한 fraction part는 0.25이므로 0.010000..00(2)가 됩니다!

따라서, 11000000101000…00로 나타낼 수 있습니다.

special value

위에서 exp에 제한을 두었습니다. 00000000000000..00과 1111…11은 안 된다고 했는데, 이유가 특별한 숫자를 표현하기 위해서입니다.

1
2
3
4
5
1. exp가 모두 0이고, fraction도 모두 0이면 숫자 0을 표현합니다.
2. exp가 모두 0이고, fraction이 모두 0이 아니라면 부동소수점 fraction 계산에서 1+fraction이 아닌, 0+fraction으로 계산합니다. 이는 정상적으로 표현할 수 있는 숫자보다 더 작은 숫자를 표현합니다. (denormal numbers)
3. 또한 exp가 모두 1이고, fraction이 모두 0이라면 부호가 있는 무한을 표현합니다. 
4. exp가 모두 1이고, fraction이 000000..0이 아니라면 NaN(Not a Number)을 나타냅니다.
5. 즉 exp가 모두 0이거나, 1이라면 special value를 표현합니다. 

2번에 대해 이야기를 해보자면, fraction을 계산할 때 1이 있다고 가정하여 하나의 비트를 더 나타낼 수 있었습니다. 하지만 이보다 더 작은 수를 나타내기 위해서 모두 exp part가 모두 0이라면 1+fraction이 아닌, 0+fraction으로 계산합니다. 이를 denormal number라고 부르는데, normal number는 가수부를 1.0에서 2.0 사이로 제한을 했습니다. 하지만 denormal number는 가수부의 제한을 제거함으로, 더 낮은 수를 나타낼 수 있게 되었습니다.

floating point addition

이제 이러한 부동소수점을 덧셈해보겠습니다.

1
2
3
4
1. 소수점 정렬. 지수가 낮은 숫자를 높은 숫자에 맞춥니다.
2. 이후 가수부를 덧셈합니다.
3. 정규화 과정을 거쳐 +-a(1.0<=a<2.0) * 2^b로 만듭니다.
4. fraction 결과가 범위를 초과한다면 반올림을 합니다.

1.000(2) × 2^(–1) + –1.110(2) × 2^(–2)을 계산해보겠습니다.

1
2
3
4
1. 1.000(2) × 2^(–1) + –0.111(2) × 2^(–1) 형태로 소수점을 정렬하고
2. 덧셈합니다. 1.000(2) × 2^(–1) + –0.111(2) × 2^(–1) = 0.001(2) × 2^(–1)
3. 정규화를 진행합니다. 0.001(2) = 1.000 * 2^(-4)입니다. 
4. fraction 부분이 범위를 초과하지 않으므로 딱히 반올림을 하지 않아도 됩니다.

즉, 1.000*(2)^-1이므로 (sign/exp/fraction)을 0/ 01111011 (123) / 00000…00000로 표현할 수 있습니다. 아래는 회로도입니다.

image

floating point multiplication

부동소수점의 곱셈에 대해 알아보겠습니다.

1
2
3
4
5
1. 지수 부분을 더합니다.
2. 곱셈 계산을 실행합니다.
3. 정규화 및 over/underflow 체크.
4. 반올림 후 재정규화
5. 부호 결정

순으로 진행합니다.

1.0002 × 2^(–1) × –1.1102 × 2^(–2) (0.5 × –0.4375)을 계산해보겠습니다.

1
2
3
4
1. 지수부는 -1 + -2 = -3입니다. 즉 bias를 포함하면 124입니다. 이는 bias를 포함한 지수부 126, 125에 127을 뺀 결과입니다. 
2. 곱셈 계산을 진행합니다. 곱하면 1.110000(2)이므로 1.110(2) x 2^(-3)입니다.
3. 정규화, 반올림 결과가 같습니다.
4. 부호는 -1 * 1이므로 음수입니다.

즉, 표현하면 1/01111100/1100000000…0000입니다. 이는 연산이 오래 걸리므로 파이프라인으로 구현 가능합니다.

마무리하며

floating point의 연산에 대해 알아보았습니다.

This post is licensed under CC BY 4.0 by the author.