오늘은 부동 소수점에 대해서 알아보겠습니다.
부동소수점(=떠돌이 소수점 방식)은 실수를 컴퓨터 상에서 근사하여 표현할 때 소수점의 위치를 고정하지 않고, 그 위치를 나타내는 수를 따로 적는 것으로, 유효숫자를 나타내는 가수와 소수점의 위치를 풀이하는 지수를 나누어 표현합니다.
(컴퓨터에서 소수점 이하의 값을 가지는 실수를 표현하는 방법)
https://ko.wikipedia.org/wiki/%EB%B6%80%EB%8F%99%EC%86%8C%EC%88%98%EC%A0%90
부동 소수점의 표현 수준
IEEE Std 754-1985
- IEEE(전지전자공학자협회)에서 1985년에 표준으로 채택
표현 방식의 다양성을 해결하고자 제안됨
- ex) 0.10100 * 2^3, 0.01010* 2^4
- 수 표기의 호환성 증대
- 1980년 이후 컴퓨터는 거의 모두 따르는 수준
표현방식
- 단일 정밀도 (Single precision, 32-bit)
- 2배 정밀도 (Double precision, 64-bit)
고정 소수점 표현형식 = (부호와 크기 표현방식, sign and magnitude)
- 정수 부분과 실수 부분의 자릿수를 고정
- 부호비트와, 각각을 나타내는 비트를 사전적으로 할당
- ex) 7.625
- 구현은 편하지만, 표현 가능한 수의 범위와 정밀도가 낮아 거의 사용되지 않음
- 이를 부동 소수점 표현방식으로 바꿔주면, 111.101 = 1.11101 * 2^2 이므로, 지수부는 10(2)을 나타내고, 가수부는 111101(2)을 나타냄
단일 정밀도(32) vs 2배 정밀도(64)
단일 정밀도 : 32비트 표현 (부호 1, 지수 8, 가수 23)
2배 정밀도 : 64비트 표현(부호 1, 지수 11, 가수 52)
- S : 부호 비트(0-> Positive, 1 -> Negative)
- 정규화된 유효자리 (significand) : 1.0 <= |유효자리| < 2.0 : 항상 1로 시작하기에, 1을 비트로는 표현 x(잠복 비트)
- 지수 : Exponent - Bias
- Exponent는 부호 없는 수
- 000...000 가장 작고, 111...111이 가장 큰 수
- 음수를 나타내기 위해 Bias를 뺌
- 단일 정밀도 : Bias = 127 2배 정밀도 : Bias = 1203
지수필드가 모두 0이거나 모두 1인 경우는 다른 수를 표현하는 데 사용하기 위함
- 00000000은 잠복비트가 없음을 나타냄 (0.xxxx)
- 지수는 1-Bias이고, 가수는 0.f
- 가수필드가 00000이라면, 전체 수는 0을 나타낼 수 있음
- 11111111인 경우
- 가수 필드가 모두 0이면 무한대 (혹은 - 무한대)
- 가수필드가 모두 0이 아니면 NaN(Not a Number)
지수필드가 00000000, 11111111 사이의 수일 때,
가장 작은 수
- 지수 필드 : 00000001 -> 실제 지수 = 1 - 127 = -126
- 가수 필드 : 000...000 -> 유효자리 = 1.0
- ±1.0 * 2^-126
가장 큰 수
- 지수 필드 : 11111110 -> 실제 지수 = 254 - 127 = 127
- 가수 필드 : 111...111 -> 유효자리 ≒ 2.0
- ±2.0 * 2^127
2배 정밀도 비트도 같은 맥락으로 위에화 비슷하게 계산할 수 있습니다. (지수 부분은 Bias가 127이 아닌 1023을 빼줘야 합니다)
오버플로 vs 언더플로
- 오버플로
- 주어진 표현방식의 범위가 작아 표현할 수 없는 경우(심각한 오류)
- 단일 정밀도 표현에서 1.0*2^130 표현 (2^127)까지 표현이 가능한데 범위를 초과한 경우
- 언더플로
- 주어진 표현방식의 정확도가 떨어져서 소수 부분을 정확히 표현할 수 없는 경우(심각한 오류 X)
실수 -> 부동 소수점으로 표현
-0.75 = (-1)^1 * 1.1(2) * 2^-1
- 부호비트 : 1
- 가수필드 : 100...000(2)
- 지수필드 : -1 + Bias = -1 + 126 = 01111110(2) (단일 정밀도), -1 + 1023 = 1022 = 01111111110(2) (2배 정밀도)
- 단일 정밀도 : 1011111101000...00
- 2배 정밀도 : 1011111111101000..00
부동 소수점 -> 실수로 표현
11000000101000..00
- 부호비트 : 1
- 가수필드 : 01000...00(2)
- 지수필드 : 10000001(2)=129
- X = (-1)^1 * (1 + 01(2)) * 2^(129-127) = -1 * 1.25(0*2^-1+1*2^-2)*2^2 = -5.0
부동소수점 덧셈
4-digit 10진수 example (9.999 * 10^1 + 1.610 * 10^-1)
- 소수점을 맞춘 후, 더 작은 지수의 수를 더 큰 지수의 수에 맞게 Shift 해줍니다 (9.999 * 10^1 + 0.016 ^ 10^1)
- 유효숫자를 더합니다 (10.015 * 10^1)
- 정규화(정수부를 1로 맞추고, 적절하게 소수점 위치 조정)하고, 오버플로/언더플로 검사 (1.0015 * 10^2)
- 필요하다면 반올림하고 다시 정규화, 오버플로/언더플로 검사 (1.002 * 10^2)
4-digit 2진수 example (1.000(2) * 2^-1 + -1.110(2) * 2^-2 = 0.5 + 0.4375)
- 소수점을 맞춘 후, 더 작은 지수의 수를 더 큰 지수의 수에 맞게 Shift 해줍니다 (1.000* 2^-1 + -0.111 * 2^-1)
- 유효숫자를 더합니다 (0.001 * 2^-1, 2의 보수 연산 진행)
- 정규화(정수부를 1로 맞추고, 적절하게 소수점 위치 조정)하고, 오버플로/언더플로 검사 (1.000 * 2^-4)
- 필요하다면 반올림하고 다시 정규화, 오버플로/언더플로 검사 (1.002 * 10^2 = 0.0625)
부동소수점 덧셈기 하드웨어
- 정수 덧셈보다 훨씬 복잡하며, 한 클럭 사이클동안 이루어지기엔 너무 과정이 깁니다.
- 부동소수점 덧셈기는 여러 클럭 사이클로 이루어집니다(파이프라인화 될 수 있음)
부동소수점 덧셈기 하드웨어
- Step1
- 어느 지수가 더 큰지를 비교하기 위해 Small ALU(산술논리연산장치)에서 두 개의 지수를 빼줍니다.
- 여기에서 나온 지수 차이를 통해 제어신호는 3개의 멀티플렉서를 제어해 줍니다(가장 왼쪽 멀티플렉서 : 큰 지수 선택, 중앙 멀티플렉서 : 작은 수의 유효자리 선택, 가장 오른쪽 멀티플렉서 : 큰 수의 유효자리 선택)
- Step2
- 작은 유효자리가 오른쪽으로 이동하고, 정규화 이전에, Big ALU를 통해 값들을 더해줍니다.
- Step3
- Big ALU에 의해 더해진 값들을 왼쪽이나 오른쪽으로 자리이동 시키고, 지수를 증가하고 감소시킵니다.
- Step4
- 자리맞춤 단계(Round)에서 최종 결과가 나오게 됩니다.
MIPS의 부동 소수점 명령어 (single, double)
부동 소수점 연산은 보조프로세서를 활용하면서, 부동소수점 레지스터에서만 동작합니다.
- 단일 정밀도 : add.s, sub.s, mul.s, div.s, c.x.s, lwc1(적재), swc1(저장)
- 2배 정밀도 : add.d, sub.d, mul.d, div.d, c.x.d, 1dc1(적재), sdc1(저장)
- 여기에서 x는 equal(eq), not equal(neq), less than(lt), less than or equal(le), greater than(ht), greater than or equal(ge)가 될 수 있습니다.
- c.x.s -> 비교 조건에 따라서 상태를 나타내는 cond 비트를 참 또는 거짓으로 만듭니다.
- bc1t(참일 때 분기), bc1f(거짓일 때 분기)
ex) ˚F To ˚C (화씨 -> 섭씨)
C code
float f2c (float fahrenheit) {
return ((5.0/9.0)*(fahr - 32.0));
}
MIPS code ($gp(global pointer 적용, 정적 데이터를 위한 전역 포인터))
f2c : lwc1 $f16, const5($gp)
lwc2 $f18, const9($gp)
div.s $f16, $f16, $f18
lwc1 $f18, const32($gp)
sub.s $f18, $f12, $f18
mul.s $f0, $f16, $g18
jr $ra
컴퓨터에서 실수를 표현하기 위한 부동소수점과 MIPS 부동소수점 명령에 대해 알아볼 수 있었습니다. 그리고 유동적으로 실수 값을 부동 소수점으로 바꿔보고, 부동소수점에서 실수로 변환하는 과정에 대해서도 공부할 수 있었습니다.
'CS' 카테고리의 다른 글
[CS] I/O 속도 개선을 위한 ios_base::sync_with_stdio(false), cin.tie(NULL), '\n' (1) | 2023.08.15 |
---|---|
[CS] 면접을 위한 CS 전공지식 노트 정리(chapter4 데이터베이스) (1) | 2023.06.05 |
[컴퓨터 구조] chapter3 정리 (컴퓨터 연산 : 덧셈, 뺄셈, 곱셈, 나눗셈) (0) | 2023.05.22 |
[CS] 복잡도, 선형 자료 구조, 비선형 자료 구조 (0) | 2023.05.20 |
[컴퓨터 구조] chapter2-3 정리 (동기화, 컴파일러, 어셈블러, 링커, 로더) (3) | 2023.05.04 |