Нормализуйте данные для интерполяционных таблиц

В этом примере показано, как нормализовать данные для использования в интерполяционных таблицах.

Интерполяционные таблицы являются очень эффективным способом записи вычислительно-интенсивных функций для встраиваемых устройств с фиксированной точкой. Например, вы можете эффективно реализовать логарифм, синус, косинус, тангенс и квадратный корень с помощью интерполяционных таблиц. Вы нормализуете входы в эти функции, чтобы создать меньшую интерполяционную таблицу, и затем вы масштабируете выходы на коэффициент нормализации. Этот пример показов, как реализовать функцию нормализации, которая используется в примерах Реализация Квадратного корня с фиксированной точкой с использованием интерполяционной таблицы и Реализация Log2 с фиксированной точкой с использованием интерполяционной таблицы.

Setup

Чтобы убедиться, что этот пример не изменит ваши предпочтения или настройки, этот код хранит исходное состояние.

originalFormat = get(0,'format'); format long g
originalWarningState = warning('off','fixed:fi:underflow');
originalFiprefState = get(fipref); reset(fipref)

Вы восстановите это состояние в конце примера.

Пример

Используйте функцию нормализации fi_normalize_unsigned_8_bit_byte, определенный ниже, для нормализации данных в u.

u = fi(0.3,1,16,8);

В двоичном формате, u = 00000000.01001101_2 = 0.30078125 (значение с фиксированной точкой не совсем 0,3 из-за округления до 8 бит). Цель состоит в том, чтобы нормализовать так, чтобы

u = 1.001101000000000_2 * 2^(-2) = x * 2^n.

Начните с u представлено как беззнаковое целое число.

High byte Low byte

00000000 01001101 Начало: u как беззнаковое целое число.

Высокий байт 0 = 00000000_2. Добавьте 1, чтобы сделать из него индекс: index = 0 + 1 = 1. Интерполяционная таблица количества начальных нулей по индексу 1 указывает, что существует 8 начальных нулей: NLZLUT(1) = 8. Слева сдвиньте это много биты.

High byte Low byte

01001101 00000000 Сдвинут влево на 8 бит.

Повторите итерацию, чтобы удалить начальные нули из следующего байта.

Высокий байт 77 = 01001101_2. Добавьте 1, чтобы сделать из него индекс: index = 77 + 1 = 78. Интерполяционная таблица количества начальных нулей по индексу 78 указывает, что существует 1 начальный ноль: NLZLUT(78) = 1. Слева сдвиньте это много биты.

High byte Low byte

100110100 0000000 Сдвинут влево на 1 дополнительный бит, всего на 9.

Повторно интерпретируйте эти биты как неподписанные фиксированные точки с 15 дробными битами.

x = 1.001101000000000_2 = 1.203125

Значение для n - размер слова u, минус длина дроби u, минус количество левых сдвигов, минус 1.

n = 16-8-9-1 = -2

И поэтому ваш результат:

[x,n] = fi_normalize_unsigned_8_bit_byte(u)
x = 
                  1.203125

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Unsigned
            WordLength: 16
        FractionLength: 15
n = int8
   -2

Сравнивая двоичные значения, можно увидеть, что x имеет те же биты, что и u, сдвинутый влево на 9 бит.

binary_representation_of_u = bin(u)
binary_representation_of_u = 
'0000000001001101'
binary_representation_of_x = bin(x)
binary_representation_of_x = 
'1001101000000000'

Очистка

Восстановите исходное состояние.

set(0,'format',originalFormat);
warning(originalWarningState);
fipref(originalFiprefState);
%#ok<*NOPTS>

Функция для нормализации неподписанных данных

Этот алгоритм нормирует неподписанные данные с 8-битными байтами. Заданные входные u > 0, а выход x нормирована таким образом, что

u = x*2^n

где 1 <= x < 2 и n - целое число. Обратите внимание, что n может быть положительным, отрицательным или нулевым.

Функциональные fi_normalize_unsigned_8_bit_byte рассматривает 8 наиболее значимых битов входа за раз и слева сдвигает биты до тех пор, пока самый значимый бит не будет равен 1. Количество бит для сдвига для каждого 8-битного байта считывается из интерполяционной таблицы количества начальных нулей, NLZLUT.

function [x,n] = fi_normalize_unsigned_8_bit_byte(u)
    assert(isscalar(u),'Input must be scalar');
    assert(all(u>0),'Input must be positive.');
    assert(isfi(u) && isfixed(u),'Input must be a fi object with fixed-point data type.');
    u = removefimath(u);
    NLZLUT = number_of_leading_zeros_look_up_table();
    word_length = u.WordLength;
    u_fraction_length = u.FractionLength;
    B = 8;
    leftshifts=int8(0);
    % Reinterpret the input as an unsigned integer.
    T_unsigned_integer = numerictype(0, word_length, 0);
    v = reinterpretcast(u,T_unsigned_integer);
    F = fimath('OverflowAction','Wrap',...
               'RoundingMethod','Floor',...
               'SumMode','KeepLSB',...
               'SumWordLength',v.WordLength);
    v = setfimath(v,F);
    % Unroll the loop in generated code so there will be no branching.
    for k = coder.unroll(1:ceil(word_length/B))
        % For each iteration, see how many leading zeros are in the high
        % byte of V, and shift them out to the left. Continue with the
        % shifted V for as many bytes as it has.
        %
        % The index is the high byte of the input plus 1 to make it a
        % one-based index.
        index = int32(bitsra(v,word_length-B) + uint8(1));
        % Index into the number-of-leading-zeros lookup table.  This lookup
        % table takes in a byte and returns the number of leading zeros in the
        % binary representation.
        shiftamount = NLZLUT(index);
        % Left-shift out all the leading zeros in the high byte.
        v = bitsll(v,shiftamount);
        % Update the total number of left-shifts
        leftshifts = leftshifts+shiftamount;
    end
    % The input has been left-shifted so the most-significant-bit is a 1.
    % Reinterpret the output as unsigned with one integer bit, so
    % that 1 <= x < 2.
    T_x = numerictype(0,word_length,word_length-1);
    x = reinterpretcast(v,T_x);
    x = removefimath(x);
    % Let Q = int(u).  Then u = Q*2^(-u_fraction_length),
    % and x = Q*2^leftshifts * 2^(1-word_length).  Therefore,
    % u = x*2^n, where n is defined as:
    n = word_length -  u_fraction_length - leftshifts - 1;
end

Интерполяционная таблица количества начальных нулей

Функциональные number_of_leading_zeros_look_up_table используется в fi_normalize_unsigned_8_bit_byte и возвращает таблицу количества начальных нулевых бит в 8-битном слове.

Первый элемент NLZLUT равен 8 и соответствует u=0. В 8-битном значении u = 00000000_2, где индекс 2 указывает основу -2, существует 8 ведущих нулевых бит.

Второй элемент NLZLUT равен 7 и соответствует u=1. Существует 7 начальных нулевых биты в 8-битном значении u = 00000001_2.

И так далее, пока последний элемент NLZLUT не равен 0 и не соответствует u=255. В 8-битном значении 0 начальных нулевых бит u=11111111_2.

The NLZLUT таблица была сгенерирована:

>> B = 8; % Number of bits in a byte

>> NLZLUT = int8(B-ceil(log2((1:2^B))))

function NLZLUT = number_of_leading_zeros_look_up_table()
%   B = 8;  % Number of bits in a byte
%   NLZLUT = int8(B-ceil(log2((1:2^B))))
    NLZLUT = int8([8    7    6    6    5    5    5    5 ...
                   4    4    4    4    4    4    4    4 ...
                   3    3    3    3    3    3    3    3 ...
                   3    3    3    3    3    3    3    3 ...
                   2    2    2    2    2    2    2    2 ...
                   2    2    2    2    2    2    2    2 ...
                   2    2    2    2    2    2    2    2 ...
                   2    2    2    2    2    2    2    2 ...
                   1    1    1    1    1    1    1    1 ...
                   1    1    1    1    1    1    1    1 ...
                   1    1    1    1    1    1    1    1 ...
                   1    1    1    1    1    1    1    1 ...
                   1    1    1    1    1    1    1    1 ...
                   1    1    1    1    1    1    1    1 ...
                   1    1    1    1    1    1    1    1 ...
                   1    1    1    1    1    1    1    1 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0 ...
                   0    0    0    0    0    0    0    0]);
end
Для просмотра документации необходимо авторизоваться на сайте