Числа с плавающей точкой

Эффективные методы реализации моделей ИИ

Constantine Korikov
Константин Кориков
PhD, AI Research Engineer
sim8 v2 10 мин
Домашнее задание 5 мин
Кодирование FP 20 мин
FP операции 15 мин
FP стандарты 15 мин
Ассемблерная эстафета 20 мин

sim8 v2

FPU-расширение поверх целочисленного ядра

Домашнее задание

Занятие 03

Числа с плавающей точкой

Кодирование

\[ x = {\color{#a07070}\pm}\; {\color{#7a9a7a}d_0}\mathbin{.}{\color{#7a9a7a}d_1}\,{\color{#7a9a7a}d_2}\, {\color{#7a9a7a}\cdots}\, {\color{#7a9a7a}d_{p-1}} \;\times\; {\color{#6a8fa5}\beta^{\,e}}\; {\color{#a09a92}\Longleftrightarrow}\; x = {\color{#a07070}\pm}\,{\color{#6a8fa5}\beta^{\,e}}\sum_{i=0}^{p-1} {\color{#7a9a7a}d_i}\,{\color{#6a8fa5}\beta^{-i}} \]
\(d_i\) цифры мантиссы, \(d_i \in \{0,\ldots,\beta{-}1\}\) \(\beta\) основание (radix) \(e\) порядок, \(e \in [e_\text{min},\; e_\text{max}]\); обычно симметрично: \(e_\text{min} = 1 - e_\text{max}\) \(p\) точность — число значимых цифр
\[ x = {\color{#a07070}\pm}\; {\color{#7a9a7a}d_0}\mathbin{.}{\color{#7a9a7a}d_1}\,{\color{#7a9a7a}d_2}\, {\color{#7a9a7a}\cdots}\, {\color{#7a9a7a}d_{p-1}} \;\times\; {\color{#6a8fa5}\beta^{\,e}}\; {\color{#a09a92}\Longleftrightarrow}\; x = {\color{#a07070}\pm}\,{\color{#6a8fa5}\beta^{\,e}}\sum_{i=0}^{p-1} {\color{#7a9a7a}d_i}\,{\color{#6a8fa5}\beta^{-i}} \]
\(d_0 \neq 0\) единственность представления, максимальная точность при данном \(p\) \(e_{\min}\) наименьшее нормальное: \(\beta^{e_{\min}}\) — провал \((0,\;\beta^{e_{\min}})\) без чисел (gradual underflow)
\[ x = {\color{#a07070}\pm}\; {\color{#a07060}0}\mathbin{.}{\color{#7a9a7a}d_1}\,{\color{#7a9a7a}d_2}\, {\color{#7a9a7a}\cdots}\, {\color{#7a9a7a}d_{p-1}} \;\times\; {\color{#6a8fa5}\beta^{\,e_{\min}}} \]
\(d_0 = 0\) ненормализованная мантисса \(e = e_{\min}\) порядок зафиксирован
Диапазон \((0,\;\beta^{e_{\min}})\) используется для кодирования очень маленьких значений ценой потери точности (gradual underflow)
x =
·
β =
p =
emax =
·
округление
ε \(= \tfrac{\beta}{2}\,\beta^{-p}\)
машинный эпсилон
ulp \(\approx 2\varepsilon\,|x|\)
шаг сетки
(unit in the last place)
|err| \(\leq \tfrac{1}{2}\,\mathrm{ulp}\)
абсолютная ошибка
при округлении до ближайшего
|err|/|x| \(\leq \varepsilon\)
относительная ошибка
при округлении до ближайшего
min: −2 · max: 1.96875
шаг: 0.03125 · значений: 128
min: −57344 · max: 57344
Emax: 15 · значений: 248

Числа с плавающей точкой

Операции

x =
y =
·
β =
p =
emax =
Каждая операция округляет точный результат до ближайшего FP-числа. Погрешность ≤ ½ ulp.
x =
y =
·
β =
p =
emax =
Поглощение: fl(x + y) = x когда |y| ≪ |x|. Малое слагаемое исчезает — x+y−x = 0, а не y.
x =
y =
·
β =
p =
emax =
Катастрофическое вычитание: значащие цифры теряются. Guard digit сохраняет ещё одну цифру при выравнивании.
x =
y =
·
β =
p =
emax =
x²−y² теряет все значащие цифры при x ≈ y. Факторизация (x−y)(x+y) избегает катастрофического вычитания.
x =
n =
·
β =
p =
emax =
Наивное суммирование накапливает ошибку O(n·ε). Алгоритм Кэхэна удерживает ошибку O(ε) независимо от n.
β =
p =
emax =
\[A_H = \sqrt{s(s-a)(s-b)(s-c)},\quad s = \frac{a+b+c}{2}\]
\[A_K = \frac{1}{4}\sqrt{(a+(b+c))(c-(a-b))(c+(a-b))(a+(b-c))}\]

Числа с плавающей точкой

Стандарты

float64
S
1 бит
E
11 бит · bias 1023
M
52 бит
float32
S
1 бит
E
8 бит · bias 127
M
23 бит
float16
S
1 бит
E
5 бит · bias 15
M
10 бит
Тип E M Значение
±0 0…0 0…0 ±0
Субнормальные 0…0 ≠ 0 (−1)S · 21−bias · 0.M
Нормальные 1…Emax любое (−1)S · 2E−bias · 1.M
±∞ 1…1 0…0 ±∞
NaN 1…1 ≠ 0 NaN
E4M3
S
1 бит
E
4 бит · bias 7
M
3 бит
E5M2
S
1 бит
E
5 бит · bias 15
M
2 бит
Тип E M Значение
E4M3  ·  bias = 2e−1−1  ·  нет ∞  ·  NaN при E=1…1, M=1…1
±0 0000 000 ±0
Субнормальные 0000 ≠ 0 (−1)S · 21−bias · 0.M
Нормальные 0001…1111 любое (−1)S · 2E−bias · 1.M
±∞ нет
NaN 1111 111 NaN
E5M2  ·  bias = 2e−1−1  ·  ±∞ как IEEE 754  ·  NaN при E=1…1, M≠0
±0 00000 00 ±0
Субнормальные 00000 ≠ 0 (−1)S · 21−bias · 0.M
Нормальные 00001…11110 любое (−1)S · 2E−bias · 1.M
±∞ 11111 00 ±∞
NaN 11111 ≠ 0 NaN

Ассемблерная эстафета

3 задания

Скалярное произведение

\(\mathbf{a} \cdot \mathbf{b} = \sum_{i} a_i b_i\)

Вектора хранятся в памяти в формате OFP8 E4M3. Пройдитесь по парам элементов, перемножьте и накопите сумму в acc как float16.

Матрица × вектор

\(\mathbf{y} = W\mathbf{x}\)

Матрица W [m,n] и вектор x [n,1] хранятся в памяти построчно в формате OFP8 E4M3. Реализуйте умножение матрицы на вектор. Результат (float16) запишите в res.

Экспонента

Входное x хранится в памяти как float16. Нет инструкции FEXP — вычислите через ряд Тейлора или тождество ex = 2x/ln 2. Результат запишите в res.