실수 하나가 각 형식에서 실제로 어떤 비트로 저장되는지 보여줍니다. IEEE 754 표준 형식(FP64·FP32·FP16)뿐 아니라 BF16·TF32·FP8·MXFP8/6/4·NVFP4까지, AI 가속기에서 쓰이는 저정밀 형식을 함께 다룹니다. 부호·지수·가수를 색으로 나눈 비트 격자와 함께 값이 계산되는 중간 과정을 단계별로 펼쳐 보여줍니다.
지수 표기 가능. 예: 1.5e-8
0x 또는 0b 접두사
값이 계산되는 과정
저장된 값의 정확한 십진수
반올림된 표시가 아니라 그 비트가 나타내는 값 그대로입니다.
같은 값을 모든 형식에 넣으면
위에 넣은 값을 각 형식으로 저장했을 때 얼마로 바뀌는지와 오차입니다. 저정밀 형식일수록 원래 값에서 멀어집니다. MX 계열은 원소 부분만 실었습니다(공유 스케일 1 기준). 실제로는 블록 스케일이 이 오차를 상당 부분 흡수합니다.
| 형식 | 비트 | 인코딩 | 저장된 값 | 상대오차 |
|---|
형식마다 규칙이 다르다
흔히 “부동소수점”이라고 하면 하나의 규칙을 떠올리지만, 아래 형식들은 특수값 처리부터 서로 다릅니다. 같은 비트 패턴이 형식에 따라 숫자가 되기도 하고 NaN이 되기도 합니다.
IEEE 754 계열 — FP64 · FP32 · FP16
표준이 정의한 형식입니다. 지수가 전부 1이면 가수가 0일 때 무한대, 0이 아니면 NaN입니다. 지수가 전부 0이면 암묵적 1 없이 비정규 수로 읽습니다. 아래 설명하는 다른 형식들은 이 규칙을 하나씩 깨뜨립니다.
BF16 — 정밀도를 버리고 범위를 지켰다
BF16은 FP32의 지수 8비트를 그대로 두고 가수만 7비트로 잘라낸 형식입니다. 그래서 표현 범위가 FP32와 같습니다. FP16은 지수가 5비트뿐이라 최대 65504에서 넘치는데, 학습 중 기울기 값이 그 범위를 벗어나면 무한대가 되어 버립니다.
BF16은 그 문제를 피하면서 FP32 변환이 거의 공짜라는 이점도 있습니다. 아래쪽 16비트를 잘라 버리면 곧 BF16이기 때문입니다. 대신 유효숫자가 약 3자리로 줄어듭니다. 위 계산기에서 같은 값을 FP16과 BF16으로 넣어 비교해 보면 이 맞바꿈이 눈에 보입니다.
TF32 — 19비트짜리 중간 지대
TF32는 지수 8비트에 가수 10비트로, BF16의 범위와 FP16의 정밀도를 합친 형태입니다. 실제 비트 수는 19비트지만 레지스터에서는 32비트 자리를 차지합니다. 저장 형식이라기보다 연산기 내부에서 쓰는 형식에 가깝습니다.
가수가 FP32보다 짧아서 최대 표현값도 FP32보다 조금 작습니다. 3.4028e38이 아니라 3.4012e38입니다.
FP8 — E4M3와 E5M2는 쓰임이 다르다
8비트 부동소수점은 두 가지가 함께 쓰입니다. 지수와 가수를 어떻게 나눌지가 다릅니다.
- E4M3는 지수 4·가수 3비트로 정밀도 쪽입니다. 최대 448까지 표현합니다.
- E5M2는 지수 5·가수 2비트로 범위 쪽입니다. 최대 57344까지 갑니다.
학습에서는 값의 분포가 다릅니다. 순전파의 활성값·가중치는 범위가 좁아 정밀도가 중요하고, 역전파의 기울기는 값의 크기가 크게 흔들려 범위가 중요합니다. 그래서 순전파에 E4M3, 역전파에 E5M2를 쓰는 조합이 흔합니다.
여기서 규칙이 갈립니다. E4M3에는 무한대가 없습니다. 지수가 전부 1이어도 가수가 전부 1일 때만 NaN이고, 나머지는 평범한 숫자입니다. 8비트밖에 없는데 무한대에 인코딩을 낭비하지 않으려는 선택입니다. 반면 E5M2는 IEEE 관행을 그대로 따라 무한대를 가집니다.
마이크로스케일링 — 블록이 스케일을 나눠 쓴다
4비트로 값을 표현하면 표현 가능한 수가 15개뿐입니다. E2M1이 담을 수 있는 값은 0, 0.5, 1, 1.5, 2, 3, 4, 6과 그 음수가 전부입니다. 이대로는 실제 텐서를 담을 수 없습니다.
마이크로스케일링(MX)은 여기에 공유 스케일을 붙입니다. 원소 32개를 한 블록으로 묶고, 그 블록 전체에 곱할 배율 하나를 따로 저장합니다. 원소는 작은 형식으로 두되 블록마다 배율을 달리해서 값의 크기 차이는 배율이 흡수하게 만드는 것입니다.
MX 계열의 스케일은 E8M0입니다. 부호도 가수도 없이 지수 8비트만 있는 형식으로, 값은 언제나 2의 거듭제곱입니다. 곱셈이 지수 덧셈으로 끝나기 때문에 하드웨어가 싸집니다. 저장값 X에 대해 배율은 2^(X−127)이고, X가 255이면 NaN입니다.
위 계산기에서 MX 형식을 고르면 스케일 입력칸이 나타납니다. 스케일과 원소를 각각 바꿔 가며 최종 값이 어떻게 조립되는지 계산 과정에서 확인할 수 있습니다.
NVFP4는 MXFP4와 무엇이 다른가
둘 다 원소는 E2M1이지만 블록과 스케일이 다릅니다.
| MXFP4 | NVFP4 | |
|---|---|---|
| 원소 형식 | E2M1 (4비트) | E2M1 (4비트) |
| 블록 크기 | 32개 | 16개 |
| 공유 스케일 | E8M0 (2의 거듭제곱만) | E4M3 (2의 거듭제곱이 아니어도 됨) |
블록이 작으면 한 배율이 담당하는 값의 범위가 좁아져 손실이 줄어듭니다. 스케일이 E4M3이면 배율을 2의 거듭제곱에 가두지 않아도 되므로 블록 안 값들에 더 잘 맞출 수 있습니다. 대신 스케일 저장 비용이 원소당 더 커지고, 곱셈이 지수 덧셈으로 끝나지 않습니다.
왜 0.1은 0.1이 아닌가
FP32에서 0.1을 넣어 보면 정확한 값이 0.100000001490116119384765625로 나옵니다. 오타가 아닙니다. 0.1은 2진수로 유한하게 적을 수 없기 때문입니다.
10진수에서 1/3이 0.333…으로 끝없이 이어지는 것과 같습니다. 2진법에서 유한하게 끝나는 소수는 분모가 2의 거듭제곱인 분수뿐입니다. 0.5나 0.25는 정확하지만 0.1은 1/10이고 10에 5라는 인수가 있어 순환합니다.
그래서 0.1 + 0.2가 0.30000000000000004가 됩니다. 두 값 모두 저장 시점에 이미 어긋나 있고, 더하면 그 오차가 드러납니다.
정수가 어긋나기 시작하는 지점
부동소수점은 정수도 정확히 담지만 한계가 있습니다. 2^24+1을 FP32로 넣으면 16777216으로 되돌아옵니다. 가수가 24비트(암묵적 1 포함)라 그보다 큰 홀수는 표현할 수 없습니다.
FP64는 이 한계가 2^53입니다. 자바스크립트의 Number가 안전한 정수 범위를 2^53−1로 두는 이유이고, 그보다 큰 정수에 BigInt가 필요한 이유입니다.
이 도구가 다루지 않는 것
| 항목 | 설명 |
|---|---|
| 블록 전체 | 공유 스케일과 원소 하나를 다룹니다. 32개(또는 16개) 원소를 한꺼번에 양자화하지는 않습니다 |
| 반올림 모드 | 가장 가까운 값, 동점이면 짝수로 반올림만 씁니다. 확률적 반올림은 다루지 않습니다 |
| 포화 규칙 | 넘칠 때의 처리는 구현마다 다릅니다. 이 도구의 규약은 아래 표에 적었습니다 |
| NaN 페이로드 | signaling과 quiet NaN을 구분하지 않습니다 |
| 2단계 스케일 | NVFP4의 텐서 단위 FP32 스케일은 반영하지 않습니다 |
모든 계산은 브라우저 안에서만 이루어지며 입력한 값은 어디에도 전송되거나 저장되지 않습니다.