[시스템 프로그래밍] 정수의 산술연산과 실수의 표현
프로그래밍 언어에는 사칙연산 말고도 여러 가지 연산이 있다.
비트 연산
두 가지 이진수를 대상으로 연산을 수행한다.
& : and
| : or
~ : not
^ : xor
논리 연산
&& / || / !
하던 대로 하면 된다.
시프트 연산
생각해야 할 부분이 좀 있다.
x << y
x >> y
x비트벡터 x를 왼쪽 혹은 오른쪽으로 y만큼 밀어내는 연산이다.
왼쪽으로 1만큼 밀어내면 2를 곱한 효과를, 오른쪽으로 1만큼 밀어내면 2를 나눈 효과를 얻는다. (소멸되는 비트를 고려하지 않을 때)
논리 시프트 (Logic) : 공백을 0으로 채운다.
산술 시프트 (Arithmetic) : 공백을 가장 중요한 비트로 채운다. (첫 번째 비트)
산술 시프트는 수 체계와 연관돼있다.
순환 시프트 (circular) : 직렬 출력을 직렬 입력에 연결한다.
y값이 음수이거나 워드 길이보다 큰 경우 비정상적으로 동작하니 주의하자.
좌측 시프트 연산 (<<) 은 Logical / Arithmetic 을 신경쓰지 않아도 되지만, 우측 시프트 연산 (>>) 에서는 주의해야 한다.
C에서 << 는 Logical Shift로 동작하고, >>는 Arithmetic Shift, >>>는 Logical shift로 동작한다.
비트 연산과 논리 연산을 이용해 여러 연산자를 만들 수 있다. (a ^ a == 0 사용)
2의 보수법은 MSB를 부호비트로 사용한다.
signed와 unsigned 타입을 함께 다룰 때 몇 가지 주의할 점이 있다.
1. 하나의 수식에서 signed와 unsigned가 동시에 등장하면 해당 수식은 명시적으로 unsigned로 변환 후 계산된다.
2. signed에서 unsigned로 형변환 시 양수일 경우 그대로 유지되고, 음수일 경우 해당 수 + 2^비트수 제곱 으로 변한다.
(직접 이진수를 십진수로 변환해보면 이해하기 쉽다)
컴퓨터에서 소숫점이 있는 숫자를 표현 할 때는 소숫점을 고정시켜서 표현하는 대신 소숫점을 이동시키면서 표현한다.
이 때 IEEE 754 표준이 사용되고, 해당 포맷을 이용해 저장된다.
IEEE 표준이 사용되기 전에는 부동소수점 방식을 사용했다.
하지만 부동소숫점 방식이 가지는 문제 때문에 IEEE 표준이 사용됨. (문제점의 대표적인 예시로는 패트리엇 미사일이 있다)
이진 소수는 논리회로 시간에 배운 내용과 동일하게 소숫점 자릿수 당 2의 음수 제곱 형태로 표현한다. (101.11 == 5.75)
이진 정수에서와 마찬가지로 시프트 연산으로 곱하고 나누는 효과를 얻는다.
수 체계 상 모든 수를 표현 할 수는 없다.
1.0에 매우 근접하는 0.11111... 은 입실론을 사용해 1.0 - ε 으로 표현한다.
분모가 2의 제곱으로 된 수가 아니면 정확하게 표현할 수 없다. 무한소수를 사용한다. (1/3 == 0.010101010101...)
컴퓨터에서는 사용할 수 있는 비트수가 제한돼있다. 즉, 특정 수는 컴퓨터에서 정확히 표현 할 수 없다.
IEEE 표준은 이 형태로 소수를 표현한 후 S M E를 인코딩해서 저장한다.
즉, 이진 소수가 등장하면 일단 이 형태로 변환할 수 있어야 한다.
S는 부호. 0혹은 1 / M은 유효숫자. 범위로 실수 값 표현 / E는 지수로 2의 지수제곱을 표현 (시프트)
M은 유효숫자로 frac 필드와 연관돼있고.
exp 필드는 자릿값을 제공하고, E 부분을 인코딩한다.
float는 32비트로 exp에 8비트 / frac에 23비트 / s에 1비트를 할당한다. (단일 정밀도)
double은 64비트로 exp에 11비트 / frac에 52비트 / s에 1비트를 할당한다. (이중 정밀도)
double이 좀 더 많은 비트를 사용하니.. 당연히 더 정밀하다고 할 수 있다.
여기서 인코딩은 exp 값에 따라 세 가지 경우로 나뉜다.
Normalized
exp가 000...0 혹은 111...1이 아닌 경우 에 사용한다.
exp = E + bias
bias = 2^e-1 - 1
여기서 e는 지수비트의 개수이다. (float는 8, double은 11)
핵심은 조정값으로 인해 +, -범위를 가지는 E를 unsigned로 변환하는 부분이다.
이렇게 설정 시 회로 구현에 이점을 가진다.
M은 이진소수를 1.xxxx 형태로 바꾼 값이다.
예시를 살펴보자.
0.00101을 IEEE 포맷으로 변환해보자.
M은 1.0100이고, E는 -3이 된다.
즉, 0.00101 = 1.0100 * 2^-3 으로 표현된다.
M을 구할 때는 형태에 맞춰 비트를 끌어내고 첫 번째 1을 제외한 나머지를 frac으로 사용한다.
frac = 000.. 이면 M은 최소 1.0 / frac = 1111... 이면 M은 최대 2.0
이렇게 유효숫자 M에서 1을 맨 앞자리수에 맞춰서 표현함으로써 비트 하나를 무료로 사용할 수 있게 된다.
딱 1비트만 무료로 사용하도록 하는게 회로 설계 측면에서도 간단하고.. 어쨌든 최적의 방법이다.
float 15213.0을 Normalized로 인코딩해보자.
1. 십진수를 이진수로 바꾸고 M을 찾아준다. 이 때 최상위 비트는 1로 고정시킨다.
2. frac이 1101101101101 이므로 E는 13이다. bias는 float 타입이니 2^8-1 이다.
3. exp는 140이다. 32비트 이진수로 표현하자. (앞자리는 부호)
4. 앞자리는 exp 뒷자리는 M (frac) 으로 저장한다.
결과 0100 0110 1110 1101 1011 0100 0000 0000 [1][8][23]
Denormalized value
exp = 000...0 인 경우에 사용한다.
E = 1 - bias (이렇게 설정 시 비정규화 값에서 정규화 값으로 부드럽게 전환할 수 있다. 가장 큰 비정규화 수 -> 가장 작은 정규화 수를 생각하면 된다.)
M = 0.xxxx.. (frac은 xxxx..)
exp = 000... 이고 frac = 000... 이면 0을 표시한다. (음수 0 양수 0의 표시가 다르다)
exp = 000... 이고 frac = 000... 이 아니면 0.0에 매우 근접한 소숫값을 나타낸다.
Special values
exp = 111... 인 경우 사용한다.
exp = 111.. 이고 frac = 000.. 이면 무한대를 표현한다. (+무한 -무한)
(1.0을 0.0으로 나누면 +무한 / 1.0을 -0.0으로 나누면 -무한.. 오버플로우를 표현할 수 있다)
exp = 111.. 이고 frac = 000.. 이 아니면 NaN(Not a Number)을 표현한다.
허수 i, 무한 - 무한, 무한 * 0 (극한값)
세 가지 인코딩으로 소수를 표현할 시 위쪽과 같은 결과를 얻는다.
0 근처에는 비정규화 값들이 위치하고, 수직선의 양 끝 부분에는 특수 값이 위치한다.
0 근처에는 비정규화 숫자들이 몰려 있다.
여기서 음수의 0과 양수의 0으로 0이 2개 존재하는데, 비정규화 숫자들의 특수한 경우라고 생각하면 된다.
부동소수점을 사용한 산술연산은 제한된 범위와 정밀도를 가지기 때문에 근사를 사용해 값을 표현해야 한다.
IEEE 포맷은 네 가지 근사 방법을 정의하고 있고, 인접 짝수 방식을 기본으로 사용한다.
인접 짝수 방식은 가운데에 걸친 수에 대해 인접한 짝수로 근사하는 방법을 의미한다.
인접 짝수 방식의 예시를 몇 개 살펴보자.
1.4 -> 1.0
1.6 -> 2.0
1.5 -> 2.0
2.5 -> 2.0
통계적인 bias를 피하기 위해서 인접 짝수 방식을 사용한다.
십진 소수와 이진 소수 모두에서 사용할 수 있다. (이진 소수에서는 바로 앞자리가 0 (짝수) 인 수로 선택한다)
IEEE방식을 사용해도 컴퓨터 시스템 상 오차가 존재 할 수 밖에 없다.
하지만, 부동 소숫점을 사용할 때 보다 오차를 훨씬 줄일 수 있다.
'Computer Science > System Programming' 카테고리의 다른 글
[시스템 프로그래밍] 프로시저 (0) | 2022.10.28 |
---|---|
[시스템 프로그래밍] 어셈블리어 - 반복문 (0) | 2022.10.24 |
[시스템 프로그래밍] 어셈블리어 - 조건문 (0) | 2022.10.23 |
[시스템 프로그래밍] 어셈블리어 (0) | 2022.10.13 |
[시스템 프로그래밍] 컴퓨터 시스템과 정보의 표현 (0) | 2022.09.15 |
댓글
이 글 공유하기
다른 글
-
[시스템 프로그래밍] 어셈블리어 - 반복문
[시스템 프로그래밍] 어셈블리어 - 반복문
2022.10.24 -
[시스템 프로그래밍] 어셈블리어 - 조건문
[시스템 프로그래밍] 어셈블리어 - 조건문
2022.10.23 -
[시스템 프로그래밍] 어셈블리어
[시스템 프로그래밍] 어셈블리어
2022.10.13 -
[시스템 프로그래밍] 컴퓨터 시스템과 정보의 표현
[시스템 프로그래밍] 컴퓨터 시스템과 정보의 표현
2022.09.15