Altifigence Academy

53 / 63 · Теория

Фиксированная точка, округление и насыщение

Задайте диапазон форматом W,F, спроектируйте округление к чётному по guard/sticky и насыщение после округления.

Предварительные знания: ширины знакового сложения и умножения, арифметический правый сдвиг и overflow.

Положение точки — контракт интерпретации битов

Фиксированная точкаФиксированная точка — представление чисел с заранее заданным положением двоичной точки: к целочисленной битовой последовательности применяют постоянный масштаб. Нужно задать разрядность, знаковость и число дробных разрядов. интерпретирует целое X как x=X2−Fx=X2^{-F}. Отдельный бит десятичной точки в оборудовании не хранится. Здесь полная signed-ширина W включает знак, F — число дробных битов. В литературе Q-обозначение по-разному включает знак в целую часть, поэтому явные W,F в интерфейсе однозначнее.

−2W−1−F≤x≤2W−1−F−2−F-2^{W-1-F}\le x\le 2^{W-1-F}-2^{-F}

При W=8,F=4 шаг 1/16, диапазон −8…7.9375. 0x18 в таком контракте означает 1.5, а не целое 24. При F=3 те же 0x18 означают 3. Соединённые проводники не гарантируют совпадения числового смысла; документируйте масштаб каждого порта.

Перед сложением выравнивают точки. При разных F расширьте значение с меньшим F и сдвиньте влево либо уменьшите больший F заданным округлением. Точная сумма двух одинаковых W,F требует W+1 бит и того же F. При умножении перемножают raw-целые, а числа дробных битов складывают.

P=XAXB,FP=FA+FBP=X_A X_B,\qquad F_P=F_A+F_B

Полное произведение двух 8-битных F=4 — signed 16 бит F=8. Для выхода 8 бит F=4 сначала удаляют четыре дробных бита, затем проверяют signed-диапазон. Если сначала усечь произведение до 8 бит, последующее насыщение уже не сможет определить исходную величину.

Отбрасывание и округление различаются

Арифметический сдвиг на d бит даёт q=⌊P/2d⌋q=\lfloor P/2^d\rfloor; отрицательные числа тоже округляются вниз. При P=−24,d=4P=-24,d=4 точное частное −1.5, q=−2, что отличается от усечения к нулю. Нельзя считать, что выбор старших битов имеет для отрицательных ту же ошибку, что для положительных.

Спроектируем round-to-nearest, ties-to-even: к ближайшему, при точной середине — к чётному целому. Старший отбрасываемый бит — guard g, OR остальных — sticky t, младший сохраняемый бит q — l.

inc=g∧(t∨l),qrnd=q+inc\mathrm{inc}=g\land(t\lor l),\qquad q_{\mathrm{rnd}}=q+\mathrm{inc}

При g=0 остаток меньше половины, ничего не меняем. При g=1,t=1 — больше половины, увеличиваем. При g=1,t=0 — точная половина, добавляем 1 только к нечётному q. Для отрицательных правило то же: с нижним частным q остаток r=P−q2dr=P-q2^d всегда удовлетворяет 0≤r<2d0\le r<2^d.

Например, −24/16=−1.5 округляется к −2, поскольку q=−2 чётно; −40/16=−2.5 тоже к −2, поскольку q=−3 нечётно. Отдельное правило «для отрицательных всегда вычитать 1» ошибочно. Без насыщения конечная числовая ошибка не больше половины выходного LSBLSB — бит с наименьшим позиционным весом. Проверяйте одновременно направление записи и правила индексации. Подробнее. Ties-to-even не гарантирует нулевую среднюю ошибку любого распределения, но уменьшает смещение, возникающее при округлении всех значений ровно посередине в одну сторону.

Преобразуем raw P=2040 из 16 бит F=8 в 8 бит F=4. 127.5 округляется к чётному 128, затем ограничивается signed-максимумом 127. Расширенную ширину нужно сохранять до последней записи.

Сначала округление, затем насыщение
  1. Вход P=2040: 16 бит · F=8
  2. Уменьшение масштаба: 2040 / 16 = 127.5
  3. равноудалённые — к чётному: Округлённое raw = 128
  4. Хранение после насыщения: raw 127 → 7.9375

Насыщение после завершения округления

Насыщение заменяет значения выше максимума максимумом, а ниже минимума — минимумом. В отличие от wrap большое положительное не превращается в отрицательное. Но корректно насытить уже суженное и перешедшее через границу диапазона значение нельзя.

Ниже полный комбинационный модуль signed 16 бит F=8 → signed 8 бит F=4. При фиксированном d=4 guard=p[3], sticky=p[2:0]. Увеличение для округления и сравнение диапазона выполняются в 17-битном signed-пространстве; 8 бит выбираются только в конце.

SystemVerilog
module requantize (
  input  logic signed [15:0] p,
  output logic signed [7:0] y,
  output logic saturated
);
  logic signed [16:0] wide, q, rounded;
  logic inc;
  always_comb begin
    wide = {p[15], p};
    q = wide >>> 4;
    inc = p[3] & ((|p[2:0]) | q[0]);
    rounded = q + (inc ? 17'sd1 : 17'sd0);
    saturated = 1'b0;
    if (rounded > 17'sd127) begin
      y = 8'sh7f;
      saturated = 1'b1;
    end else if (rounded < -17'sd128) begin
      y = 8'sh80;
      saturated = 1'b1;
    end else begin
      y = rounded[7:0];
    end
  end
endmodule

При P=2040 частное P/16=127.5 округляется к чётному 128 и насыщается до 127. Конечное значение — 7.9375. Проверка только q=127 до округления пропустила бы переполнение. Saturated сообщает ограничение числового диапазона, а не просто потерю дробных битов.

При обобщении отдельно обрабатывайте d=0 без отбрасываемых битов и d=1 без области sticky. Скрытие недопустимого part-select внутри условия может не устранить ошибку elaboration.

Округление и насыщение добавляют сумматоры, компараторы, MUXМультиплексор — комбинационная схема, соединяющая один из нескольких входов с выходом по сигналу выбора. Соответствие битов выбора и номеров входов должно быть задано явно. Подробнее и задержку и выбираются отдельными политиками. Такое разделение отражено и в документации AMD о фиксированной точке. При накоплении нескольких членов заранее решите, сохранять ли промежуточную ширину и преобразовывать один раз в конце. Поэтапное насыщение может нарушить ассоциативность сложения, а повторное округление — накапливать малые ошибки.

Попробуйте сами

Signed-вход P ширины 16, F=8 преобразуется в signed ширины 8, F=4. Для P=24,40,−24,−40,2040 найдите floor-частное q, guard/sticky, округлённое целое, конечный raw и реальное значение. Чем опасна проверка насыщения до округления для 2040?

Прочитать объяснение

У всех входов младшие четыре бита 1000, поэтому guard=1, sticky=0. P=24: q=1 (нечётное)→2, raw=2, значение 0.125. P=40: q=2 (чётное)→2, raw=2, 0.125. P=−24: q=−2 (чётное)→−2, raw=−2, −0.125. P=−40: q=−3 (нечётное)→−2, raw=−2, −0.125. P=2040: q=127 (нечётное)→128, выше signed-максимума 8 бит, поэтому raw=127, значение 7.9375, saturated=1. Проверка только q=127 до добавления 1 в 8 битах могла бы дать wrap в 0x80 и выход −8. Увеличение и сравнение нужно завершить в расширенном signed-значении.

Выбор действует в этом браузере. Его можно изменить внизу страницы.