컴퓨터에서 실수를 표현하는 방식에는 두 가지 방식이 있다.
바로 고정 소수점 방식과 부동 소수점 방식이다.
부동 소수점을 표시하는 형태를 정의한 표준을 IEEE Std 754-1985라고 한다.
S : 부호를 표시하는 sign bit이며 0이면 양수, 1이면 음수이다
Exponent : 지수부를 의미한다, actual exponent는 Bias값을 빼주어야한다
Fraction : 가수부를 의미한다 여기서 1을 더해주는 이유는 어떤 이진수든 1을 포함하고 있기 때문에 부동 소수점의 format의 통일성을 주는 것이다
Significand : 여기서 (1 + Fraction) 을 Significand라고 한다
부동 소수점을 표시하는 방법에는 Single Precision과 Double Precision이 있다. 위 그림은 Single Precision의 예시 사진이다.
Single Precision
float
자료형에 해당한다Double Precision
double
자료형에 해당한다즉, Double Precision이 Single precision보다는 수를 더 세밀하게 나타낼 수 있다.
actual Exponent값에 bias값을 더해주어 signed로 표현해야 더 작은수까지 나타낼 수 있다
비교와 정렬의 복잡도가 낮아진다
Exponent Filed에 저장되는 값과 actual Exponent 값은 다름을 주의해야한다.
Exponent Field = actual Exponent + Bias
actual Exponent = Exponent Field - Bias
여기서 Bias값은 Single Precision에서는 127, Double Precision에서는 1023이다.
예약값은 Exponent Field가 0일 때와 255일 때이고, 특정 표현으로 표기하기로 약속돼있다. 최솟값은 Exponent Field가 1일 때, 최댓값은 Exponent Field가 254일 때이다.
Single Precision과 똑같은 매커니즘으로 구할 수 있다.
double precision은 메모리에 다음과 같이 저장이 된다.
1비트의 sign bit와 11비트의 exponent, 52 비트의 fraction으로 저장이 되는데, 32비트의 word 단위로 쪼개서 저장을 한다.
각 비트 값을 보고 정규식으로 변환, 다시 10진수로 변환한다
가끔 우리가 예상했던 것보다 결과 값이 매우 작게 나오는 경우도 있다.
예를 들어, Single Precision에서 A x 2^127과 B x 2^3을 곱해준다.
그러면 결과는 A x B x 2^130으로, 8비트만 사용하는 Exponent Field가 overflow가 나게 된다.
1 0000 0010 에서 MSB인 1이 사라지고 0000 0010으로 나타나게된다. 따라서 Signed로 표시하면 -125의 결과 값이 나온다.
이런 경우 우리는 Single -> Double Precision으로 format을 바꿔주면 이러한 overflow나 underflow 현상을 예방할 수 있다.
C언어에서는 float -> double로 형변환을 해주곤한다.
절댓값의 크기가 아주 작은 수를 표현할 때를 위해 사용한다.
Fraction에 더해주던 hidden bit를 1이 아닌 0으로 해준다
denormal number를 사용해주면 0과 1사이의 숫자 두 개를 곱할수록 숫자가 0에 수렴해 underflow에 가까워지는 경우를 막아줄 수 있다
위에서 부동 소수점의 덧셈 연산을 해주었는데, 이 연산기를 어떻게 구현할지 보자. 위 그림 오른쪽 상단의 예제에서 -0.5를 A, -0.4375를 B라고하자.
step1
step2
step3
step4
부동 소수점의 곱셈은 덧셈보다 더 쉽다
왜냐하면 exponent를 맞춰 줄 필요가 없고, 그에 따른 significand를 정렬해줄 필요가 없기 때문이다.
다음과 같이 FP에 대한 연산이면, 접두사로는 Floating을 의미하는 F가, 접미사로는 S(Single)와 D(Double)가 붙는다.
IEEE Std 754에서는 FP 연산시 유효숫자 이외에는 반올림을 하는데, 만약 유효숫자가 3자리라면 3자리로 절삭을 해버리고 연산을 하는게 아니고, 뒤에 두 비트 정도를 extra bit로 남긴 후 연산을 하고 반올림을 해 연산의 정확성을 높인다.
이에 따르면 extra bit를 반올림시 0~49이면 내림이 되고 50~99이면 올림이 된다.
대신 이렇게 연산을 세부화하면 연산의 정확성은 좋아지나, 하드웨어 cost가 들고 복잡도가 더 늘어난다.
그래서 하드웨어 설계 시 trade off가 있으므로 이를 고려하고 필요에 따라 연산의 방식을 설계하면 된다.
이미지 처리나 뉴럴 네트워크 연산에서는 FP 연산이 필요한 경우가 많다.
그래서 128비트를 여러 개로 쪼개서 여러 개의 데이터를 넣고 각각의 데이터를 벡터로 취급해 한 번의 연산에 여러 개의 데이터를 처리하는 SIMD라는 아키텍처가 존재한다.
ARMv8에서는 SIMD 아키텍처에 기반한 연산을 다음의 명령어로 지원한다.
레지스터는 V라는 레지스터를 사용한다
V1.16B라고 하면 128비트를 Byte단위로 16개의 벡터로 쪼개어 계산을 한다.
총 16개의 데이터를 한 번에 연산할 수 있다
V1.4S면, 128비트를 Single precision(32비트) 단위로 4개의 벡터로 쪼개어 계산을 한다
총 4개의 데이터를 한 번에 연산할 수 있다