서울대학교 컴퓨터공학과 이재진 교수님의 "확장형 고성능 컴퓨팅" 강의를 필기한 내용입니다.

FP Representation

  • 실수는 무한대이기 때문에 64 (32) bit 로 나타내는 것 (FP) 은 어쩔 수 없이 one-to-many 관계이다.
  • 어쨌든 이거랑 관련있는 표준은 IEEE 754 이다.
  • Scientific notation
  • 개의 숫자를 사용하여 실수를 표현할 때,
    • 고정소수점 (Fixed-point): 말 그대로 소수점의 위치를 고정시켜놓은 것
      • 가령 8개의 digit 을 사용하고, 소수점 아래 자리수가 2 인 고정소수점의 표현은 부터 까지이다.
    • 부동소수점 (Floating-point): 말 그대로 소수점의 위치를 고정시키지 않은 것
      • 가령 마찬가지로 8개의 digit 을 사용한다 했을 때, 부동소수점으로 표현되는 값은 형태이고, 범위는 부터 까지 이다.
  • 정밀도 (Precision) 는 실수를 표현하는데 몇개의 bit 를 사용했냐 정도로 생각하면 된다.
    • Precision 은 (IEEE 754 에 따르면) 16, 32, 64 .. 이렇게 있다.
      • 16 은 half, 32 은 single (float), 64 는 double (double), 128 은 quadruple, 258 은 octuple 이런식으로 부른다.
    • 십진수로 바꿔서 생각했을 때, single precision 의 경우에는 실수를 표현하는 숫자의 개수 (위에서 ) 이 7개이고, double precision 의 경우에는 15개이다.

IEEE 754

Format

  • 위 그림의 오른쪽 처럼 Sign bit (, 크기는 1-bit) + Exponent (, 크기는 -bit) + Fraction (, 크기는 -bit) format 이다.
  • Fraction 은 mantissa 를 보정한 값 ()
    • Mantissa 는 이기 때문에 1을 빼서 fraction 은 에 들어오도록 한 것
    • 이렇게 보정한 것을 Normalized value 혹은 Normal value (정규값) 이라고 한다.
  • Exponent 는 를 더한 것
    • Exponent 은 unsigned 이기 때문에 음수 exponent 에 를 더해서 양수로 만듦
    • 로 구한다.
  • Exponent 가 모두 0이면 Sub-normal 으로 아주 작은 값을 표현
    • 여기서는 mantissa 를 사이로 표현
    • 즉, fraction 이 보정되지 않고 () 그냥 mantissa 가 된다.
    • 이렇게 0~1 사이의 값은 보정하지 않고 표현하는 것을 Sub-normal value 혹은 Denormalized value (비정규값) 이라고 한다.
  • 나머지 이나 , 를 제외하면 나머지는 일반적인 너가 아는 그 실수 (정규화된 값)
    • , 인 경우

라운딩

  • Rounding 은 반올림 규칙… 인데 그냥 x.5 이상이면 올리는게 아니라 종류가 더 있다 (위 그림)
    • 맨 위에가 짝수 라운딩: x.5 의 경우 x 가 짝수가 되게 함
      • IEEE 754 에서는 이 방법을 사용한다.
    • 두번째는 일반적으로 알고 있는 반올림
    • 세번째는 올림이고
    • 네번째는 내림
    • 마지막은 양수면 내림, 음수면 올림
  • 라운딩 오차 (Rounding error, Round-off error) 는 원래 값과 반올림한 값 간의 차이임
    • 절대오차 (Absolute error) 는 진짜 값의 차이고
    • 상대오차 (Relative error) 는 절대오차를 원래 값으로 나눈 백분율이다.
  • IEEE 754 의 이진수 라운딩을 보자
    • 소수점 아래 둘째자리로 반올림하는 경우
      • 는 당연히 가까운 수로 반올림하면 가 된다.
      • 의 절반인 보다 크기 때문에 로 반올림된다.
      • 와의 거리가 로 같기 때문에, 짝수가 되도록 (즉, LSB 가 0이 되도록) 반올림하면 가 된다.
      • 와의 거리가 로 같기 떄문에 짝수가 되도록 반올림하면 가 된다.

Overflow, Underflow

  • Overflow 정규값을 넘어가는 범위를 overflow 라고 하고 이건 로 표현
    • 에 대한 연산은 static rule 로 처리됨
      • 가령 와 정규값 간의 대소비교는 무조건 가 크는 등
    • Binary representation 은 위에서 설명한 대로 이고 일 때이다.
  • Underflow: Subnormal 보다 작아지는 범위는 underflow 라고 함
    • 즉, normalized value 의 min 보다 더 작은 값을 표현하기 위해 subnormal value 가 완충제의 역할로 정의된 것이고
    • 이것보다도 더 작은 값들에 대해 underflow 가 나는 것
    • Underflow 시에는 제일 가까운 subnormal 혹은 0 으로 라운딩한다.

Not a Number (NaN)

  • 와 같은 경우 NaN 으로 표현하는데
  • Binary representation 은 위에서 설명한 대로 이고 일 때이다.
  • 이놈과 연산하면 무조건 가 나오고
  • 이놈은 대소비교가 불가능하다.

Operation

FP 의 결합법칙

  • 실수는 덧셈과 곱셈에 대해 결합법칙이 성립하지만
  • FP 에서는 성립하지 않는다: 아마 연산후 IEEE754 로 고치는 과정에서의 라운딩 때문일듯
  • 덧셈은 exponent 를 일치시킨 뒤 덧셈을 하고 다시 IEEE754 에 맞게 고친다. (rounding 하고 exponent 와 mantissa 를 조정)
    • exponent 를 맞추는 것은 SHIFT 로 가능하다.
  • 뺄셈은 그냥 sign bit 를 뒤집어서 음수로 만든 다음 더한다.
  • 곱셈은 간단하다
    • Exponent 는 더하고
    • Mantissa 는 곱하면 됨
    • 여기다가 그냥 IEEE754 를 씌우면 된다.
  • 나눗셈도 비슷하다: Exponent 는 빼고, Mantissa 는 나눈다.
  • 대부분은 이 연산을 빠르게 하기 위한 별도의 HW 를 분리: FPU (Floating-point Unit)

Fused Instruction Set

  • FP 연산에 대한 Fusing 을 제공하기도 한다.
    • 곱셈 다음에 덧셈을 하는 경우가 많아서
    • Fused Multiply-Add (FMA) instruction set 을 제공
      • 내적 (dot) 연산 (즉, 행렬곱 = ) 에 유용
      • FMA 를 recurse 해주면 되자나?
      • 이 연산에 대한 SIMD vectorize 도 있다.
    • 그리고 MAC (Multiply-accumule) 도 있다
      • 말그대로 곱해서 축적
  • 이들은 x86 FMA3, FMA4 에 정의돼 있다.

x86 80bit Extended Precision

  • x86 80bit Extended Precision 은 이름 그대로 FP 를 80bit 로 표현
  • 근데 저장할 때는 96bit (32bit system 의 경우, 64bit system 에서는 128bit) 를 사용
    • Alignment 를 위해
    • 즉, int 의 4byte 와 align 되게 하기 위해 이렇게 한다.
  • 여기서는 NaN 이 두가지임: Quiet NaN (QNaN), Signaling NaN (SNaN)
    • 이 둘 차이는 exception 이 나냐 안나냐의 차이임 (SNaN 이 excep)
  • Bias 는 이다.
  • 이놈은 compiler 나 그런데에서 option 을 켜줘야 사용할 수 있음: 기본적으로는 IEEE 754 로 간다

그 외의 것들..

  • BF16: exponent 8, mantissa 7 (mantissa 를 줄인 format)
  • TF, TensorFloat: NVIDIA A100 부터 지원하는 포맷으로, mantissa 만 줄여서 더 빠르게 연산할 수 있게 한다.
    • Mantissa 를 23 -> 10 로 라운딩
    • AI 학습에는 그만큼의 precision 이 필요하지 않기 때문에 그걸 희생하고 speed 를 가져오는 것