본문 바로가기
Computer Science/Computer Architecture

3. Floating-Point Arithmetic

by Gofo 2021. 5. 16.

Floating-Point Arithmetic

Floating-point를 이용할 경우 매우 작은 수와 매우 큰 수를 표현할 수 있다.

매우 작은 수와 큰 수를 다루는 과학 계산을 위해 만들어졌으며, 소수점이 있는(non-integer) 수를 표현할 수 있다.

 

+9.5와 같이 작은 수는 fixed-point를 사용해서 충분히 표현 가능하다.

 

Normalized

Floating-point는 significand(유효숫자) + exponent(지수)로 나눠서 표현한다.

표현 방법이 여러 개가 될 수 있기 때문에 normalized 방식으로 표현한다.

 

Normalized는 소수점 왼쪽에 하나의 0이 아닌 수로 유효숫자를 표현하는 것을 말한다.

예를 들어 $-2.34 \times 10^{56}$은 normalized이다.

$-0.234 \times 10^{57}$은 normalized가 아니다.

 

Floating-point Standard

네트워킹이 발전하던 시기에 모든 컴퓨터가 연결되는데 각 컴퓨터마다 floating 표현 방식이 달랐다.

따라서 통일할 필요가 있었고 1985년에 IEEE Std 754가 제정되었다.

 

표준에서는 2개의 표현 방식을 정의한다.

  • Single precision
    • 32bit를 사용한다.
    • C에서의 float type이다.
  • Double precision
    • 64bit를 사용한다.
    • C에서의 double type이다.
    • single precision보다 fraction에 더 많은 bit를 사용하기 때문에 더 정확한 표현이 가능하다.

 

 

이후 2008년에 IEEE Std 754는 Binary 32, 64, 128, 16, 256로 확장되었다.

 

Binary FP 표현

  • fraction
    • 2진법에서 non-zero는 항상 1로 정해져있기 때문에 유효숫자에서 소수점 왼쪽은 항상 1이 된다.
    • 따라서 bit 수를 절약하기 위해서 significand은 1 + fraction으로 나눠서 표현한다.
  • S
    • 하나의 bit를 이용하여 0이면 양수, 1이면 음수를 나타낸다.
  • exponent
    • 2의 제곱수로 나타낸다.
    • 지수는 (exponent + bias)로 나타낸다.
      • 이를 통해 음수인 지수를 표현할 수 있다.
      • Single precision에서는 Bias 127을 사용한다.
      • Double precision에서는 Bias 1023을 사용한다.

 

예를 들어, -0.75는 다음과 같이 표현된다.

$-0.75 = 2^{-1} + 2^{-2} = -0.11_2 = (-1)^1 \times 1.1_2 \times 2^{-1}$

  • S = 1
  • Fracton = $1000...00_2$
  • Exponent = -1 + Bias
    • Single : -1 + 127 = 126 = $0111 \, 1110_2$
    • Double : -1 + 1023 = 1022 = $011 \, 1111 \, 1110_2$
  • Single : 1 01111110 10000000000000000000000
  • Double 1 0111111110 100000000000000...00000

 

특수 표현

Exponent bit의 000...00과 111...11은 특수한 결과를 표현하기 위해 보전된다.

Exponent
(Exponent-Bias의 결과)
Fraction 표현
111...11 not 0 NaN(not a number)
111...11 0 +/- infinity
실제 수학에서는 개념일 뿐이지만, FP는 인공적인 연산이기 때문에 무한대를 제공
000...00 not 0 0
000...00 0 even smaller number

 

Single Precision vs.  Double precision

Double precision은 single precision에 비해 exponent bit가 3bit가 더 많다.

그러나 이는 실제 exponent가 $10^{300}$ 가까이 더 큰 수/작은 수를 표현할 수 있는 결과를 가져온다.

 

  • single precision
    • smallest
      • exponent : 0000001 => 실제 : 1-127 = -126
      • fraction : 000...0 => 실제 significand : 1.0
      • $\pm 1.0 \times 2^{-126} \approx \pm 1.2 \times 10^{-38}$
    • largest
      • exponent : 11111110 => 실제 : 254-127 = +127
      • fraction : 111...1 => 실제 significand : $\approx$ 2.0
      • $\pm 2.0 \times 2 ^{127} \approx \pm 3.4 \times 10^{38}$
  • double precision
    • smallest
      • exponent : 0000...01 => 실제 : 1-1023 = -1022
      • fraction : 000...0 => 실제 singificand = 1.0
      • $\pm 1.0 \times 2^{-1022} \approx \pm 2.2 \times 10^{-308}$
    • largest
      • exponent : 1111....10 => 실제 : 2046-1023 = +1023
      • fraction : 111...11 => 실제 significand : $\approx$ 2.0
      • $\pm 2.0 \times 2^{1023} \approx \pm 1.8 \times 10^{308}$

 

표준 제정 당시 하드웨어의 구현이 힘들었기 때문에 가급적 single precision을 사용하였다.

그러나 정밀 표현이 힘들고 표현 범위가 작기 때문에 single precision이 제한되면 double precision을 사용하였다.

과학 계산은 대부분 double precision을 사용하였다.

 

오늘날의 범용 컴퓨터는 강력하기 때문에 floating point 계산은 주로 double을 사용한다.

다만 작은 embedded인 경우는 더 작은 공간을 사용하기 위해 float을 사용한다.

 


Floating-Point의 문제

FP 연산은 FP ALU(FP coprocessor)에서 수행된다.

Coprocessor란, FP 연산을 넣고 FP instruction이 늘어난다는 의미를 담는다.

 

근사 계산 문제

모든 경우에서 결국 fraction bit는 제한되어있기 때문에 범위를 넘어서면 근사 계산이 발생한다.

결국 모든 floating point 연산은 근사 계산을 위해 사용된다.

 

반면 integer 연산은 정확한 연산 결과를 나타낸다.

 

또한, FP 연산은 overflow 뿐 아니라, underflow의 결과도 낳는다.

  • overflow
    • exponent의 범위를 넘어서는 경우 표현이 불가능하다.
  • underflow
    • 값이 너무 작기 때문에 표현이 불가능하다.
    • 예 : $10^{-300} \times 10^{-300}$은 표현이 불가능하다.

 

계산 순서의 문제

x + y + z의 연산에서 (x + y)를 먼저하는지, (y + z)를 먼저하는지에 따라서 연산 결과가 달라질 수 있다.

이는 FP 연산이 근사계산이기 때문에 발생하는 문제이다.

 

그리고 컴파일러마다 연산하는 순서가 다르기 때문에 발생한다.

그러나 매우 큰 수를 다루는 과학계산에서 이정도의 오차는 큰 영향을 주지 않기도 한다.

 

예를 들어, 아래에서 (x+y)을 먼저 계산하면 1이나오지만, (y+z)를 먼저 계산하면 0이 나온다.

 

x + (y + z)에서 y + z을 계산한 결과의 fraction이 23bit을 넘어서기 때문이다.

따라서 fraction은 23bit에서 잘리고, 잘릴 때 버림 혹은 반올림이 된다.

 

Floating-point comparision

아래와 같은 코드에서 첫번 째 print 문은 수행 되지만, 두번 째 print문은 수행되지 않을 수 있다.

이는 fraction의 bit를 초과하는 문제가 발생하기 때문이다.

 

첫번째 if문에서 1.5 * 2.0을 표현하는데에는 몇 bit면 충분하다.

그러나 두번째 if문에서 0.1을 표현하는데에는 23bit보다 더 많은 fraction bit가 필요하게 되고, 결국 중간에 잘려서 000...00이라는 fraction을 가지게 된다.

따라서 두 번째 if문의 조건을 충족하지 못하게 되며, print가 수행되지 않는다.

float x, y;
x = 1.5;
y = 2.0;
if((x*y) == 3.0) printf("equal\n"); // 수행 O

x = 0.1;
y = 10.0;
if((x*y) == 1.0) printf("equal\n"); // 수행 X

 

이를 해결하기 위해 floating point의 equality는 $|x - constant| < \varepsilon$을 사용한다.

이는 목표하는 수와 연산의 결과 값이 일정 정도($\varepsilon$) 이하로 차이나면 동일하게 여긴다는 것이다.

 


Floating-Point Arithmetic

Floating-Point Arithmetic

FP arithmetic hardware(FP ALU)는 주로 다음과 같은 기능을 제공한다.

  • addition, subtraction, multiplication, division, reciprocal, square-root 등의 연산
  • FP ↔ Integer conversion

 

FP의 연산은 integer에 비해 훨씬 더 복잡한 과정을 거친다.

때문에 더 오랜 시간이 걸리고, 한 cycle에 수행되지 않고 여러 cycle에 걸쳐서 수행된다.

 

다만 성능의 개선을 위해 pipeline 된다.

 

Integer 연산은 mult가 add에 비해 느렸지만,

FP 연산은 mult와 add의 복잡도가 유사하여 속도가 비슷하다.

 

Floating-Point 연산을 한 cycle에 수행하지 않는 이유?

Integer 연산은 주로 한 clock cyle에서 수행되지만, FP 연산은 여러 cycle에 걸쳐서 수행된다.

FP 연산이 수행하는데 더 오랜 시간이 걸리기 때문이다.

 

만약 FP 연산을 한 cycle에 수행하게 한다면, 전체 instruction의 cct가 길어지게 된다.

이는 컴퓨터의 전체적인 성능을 저하시키게 한다.

따라서 FP는 여러 cycle에 걸쳐 수행된다.

 

대신 FP의 수행 속도를 높이기 위해서 pipeline을 이용한다.

 

Floating-Point Addition

  1. 두 수의 exponent를 맞춰준다.
    • 절댓값이 더 작은 쪽으로 shift를 한다.
  2. significands의 덧셈을 실시한다.
  3. 결과를 normalized로 바꾸고, overflow나 underflow가 있는지 확인한다.
  4. fraction bit의 표현범위를 넘어서는지 확인한다.
    • 넘어선다면 버림이나 반올림을 실시한다.
    • 이 때 normalized format이 깨질 수 있으니 normalized format으로 맞춰준다.

 

예를 들어, $1.000_2 \times 2^{-1} + -1.110_2 \times 2^{-2}$을 수행한다고 하자.

  1. exponent 맞춰주기
    • $1.000_2 \times 2^{-1}$는 그대로
    • $-1.110_2 \times 2^{-2} \; \rightarrow \; -0.111_2 \times 2^{-1}$
  2. significands 덧셈 실시
    • $(1.000_2 + -0.111_2) \times 2^{-1}$
    • $= 0.001_2 \times 2^{-1}$
  3. 결과를 normalized로 바꾸고, overflow/underflow 확인
    • $0.001_2 \times 2^{-1} \rightarrow 1.000_2 \times 2^{-4}$
    • overflow/underflow 없음
  4. fraction bit의 표현범위를 넘어서는지 확인
    • 넘어서지 않는다.
  5. 결과
    • $1.000_2 \times 2^{-4}$

 


MIPS FP Instruction

FP hardware(FP ALU)는 ISA을 확장하는 coprocessor(adjunct processor)이다.

Floating point 연산을 위해서 추가적인 instruction set과 추가적인 register가 존재한다.

 

FP Register

FP data를 담는 32개의 FP register가 존재한다.

따라서 32bit MIPS의 총 register는 64개가 된다.

 

Single precision은 하나의 register를 사용한다.

<pre>$f0, $f1, $f2, ...</pre>

 

Double precision은 2개의 register을 묶어서 한 쌍으로 사용한다.

<pre>$f0/$f1, $f2/$f3 ...</pre>

 

 

FP Register의 사용 & 구분

FP instruction은 오직 FP register만을 사용한다.

따라서 opcode를 보고 어떤 register을 사용할 지 결정할 수 있다.

 

이를 통해 register을 구분하기 위한 register operand의 bit 수가 늘어날 필요가 없다.

Opcode를 보고 register을 구분함으로써 5개의 bit 만으로도 register을 판별할 수 있는 것이다.

 

FP Instruction

FP operation을 위한 별도의 instruction이 있다.

FP instruction은 FP register만을 이용한다.

  • Load/Store
    • single precision
      • lwc1, swc1
      • 예 : <pre>lwc1 $f8, 32($sp)</pre>
    • double precision
      • ldc1, sdc1 ...
  • Arithmetic
    • single precision
      • add.s, sub.s, mul.s, div.s
    • double precision
      • add.d, sub.d, mul.d, div.d
  • Comparision
    • c.lt.s, c.lt.d, c.le.s, c.le.d ...
    • 예 : <pre>c.lt.s $f3, $f4</pre>
  • Branch
    • bc1t, bc1f

 

 

'Computer Science > Computer Architecture' 카테고리의 다른 글

3. MIPS ISA  (0) 2021.05.16
3. Multimedia Arithmetic  (0) 2021.05.16
3. Integer Arithmetic  (0) 2021.05.16
3. Computer Arithmetic  (0) 2021.05.16
2. Compile, Link, Run  (0) 2021.05.09

댓글