Эффективные методы реализации моделей ИИ
Как считает CPU
Как использовать отрицательные числа?
1) Как кодировать знак: 1 и 0?
2) Как выполнять вычитание?
3) Как представлять нуль?
Прямой код
В прямом коде знак хранится отдельно: старший бит отвечает за знак, а остальные биты — за модуль. Поэтому ноль получается в двух вариантах: 0000 = +0 и 1000 = -0.
Из-за раздельной обработки знака и модуля одного стандартного сумматора мало — обычно нужен дополнительный блок логики.
0011 = 3 + 1001 = -1 ------ 0010 = 2
Обратный код
В обратном коде отрицательное число получается простой инверсией битов, поэтому арифметика выглядит почти как обычное сложение. Но у нуля снова два состояния: 0000 = +0 и 1111 = -0.
Сумматор можно использовать стандартный, но после сложения нужен шаг коррекции переноса с циклическим добавлением единицы.
0011 = 3 + 1110 = -1 ------ 1 0001 = 1 + 1 ------ 0010 = 2
Дополнительный код
В дополнительном коде отрицательные числа задаются как инверсия плюс единица, и это даёт единое представление нуля: только 0000 = +0.
С аппаратной точки зрения вычитание сводится к операции сложения, поэтому достаточно стандартного сумматора без отдельного блока обработки знака.
0011 = 3 + 1111 = -1 ------ 1 0010 = 2 0010 = 2
От целого числа к фиксированной точке
| Операция | Формула | Пример |
|---|---|---|
| Кодирование | $p, q \in \mathbb{Z},\; q > 0,\; \text{НОД}(|p|,q)=1$ | 3/4 |
| ↳ Бинарно | 2 целых числа | 0000 0011 / 0000 0100 |
| Сложение | $\dfrac{a}{b} + \dfrac{c}{d} = \dfrac{ad + bc}{bd}$, сократить | 1/2 + 1/3 = 5/6 |
| Вычитание | $\dfrac{a}{b} - \dfrac{c}{d} = \dfrac{ad - bc}{bd}$, сократить | 3/4 − 1/4 = 1/2 |
| Умножение | $\dfrac{a}{b} \times \dfrac{c}{d} = \dfrac{ac}{bd}$, сократить | 2/3 × 3/4 = 1/2 |
| Деление | $\dfrac{a}{b} \div \dfrac{c}{d} = \dfrac{ad}{bc}$, сократить | 2/3 ÷ 4/3 = 1/2 |
$\mathbb{Z} \subset \mathbb{Q} \subset \mathbb{R}$
| Операция | Формула | Пример (Q4.4) |
|---|---|---|
| Кодирование | $\text{Q}m.n:\; \mathrm{int} = \lfloor x \times 2^n \rfloor,\; x = \mathrm{int} \times 2^{-n}$ | ⌊6.75 × 2⁴⌋ = 108 (6.75) ⌊6.7 × 2⁴⌋ = 107 (6.6875) |
| ↳ Бинарно | одно целое число | 0110 1100 (6.75) |
| Сложение | $\mathrm{int}_a + \mathrm{int}_b$ | 24 (1.5) + 12 (0.75) = 36 (2.25) |
| Вычитание | $\mathrm{int}_a - \mathrm{int}_b$ | 24 (1.5) − 12 (0.75) = 12 (0.75) |
| Умножение | $(\mathrm{int}_a \times \mathrm{int}_b) / 2^n$ | [24 (1.5) × 12 (0.75)] / 2⁴ = 18 (1.125) |
| Деление | $(\mathrm{int}_a \times 2^n) / \mathrm{int}_b$ | [24 (1.5) × 2⁴] / 12 (0.75) = 32 (2.0) |
$\text{Q}m.n \subset \mathbb{Q} \subset \mathbb{R}$
Закодируем фиксированную точку на ассемблере
Формат: Q4.4, 1 байт на число.
Реализуйте сложение и вычитание двух Q4.4 чисел в регистрах.
Умножение в фиксированной точке
Формат: Q2.2. Реализуйте умножение двух чисел.
А как сделать деление?
Расширение симулятора под float
Предложите архитектуру расширения симулятора для поддержки чисел с плавающей точкой. Опишите формат данных (знак, экспонента, мантисса) и минимальный набор операций.