Этот пример показывает, как нормировать данные для использования в интерполяционных таблицах.
Интерполяционные таблицы являются очень эффективным способом записать, что в вычислительном отношении интенсивные функции для фиксированной точки встроили устройства. Например, можно эффективно реализовать логарифм, синус, косинус, касательную и квадратный корень с помощью интерполяционных таблиц. Вы нормируете входные параметры к этим функциям, чтобы произвести меньшую интерполяционную таблицу, и затем вы масштабируете выходные параметры коэффициентом нормализации. Этот пример показывает, как реализовать функцию нормализации, которая используется в Квадратном корне Фиксированной точки Реализации в качестве примера Используя Фиксированную точку Интерполяционной таблицы и Реализации Log2 Используя Интерполяционную таблицу.
Настройка
Чтобы гарантировать, что этот пример не изменяет ваши настройки или настройки, этот код хранит исходное состояние, и вы восстановите его в конце.
originalFormat = get(0, 'format'); format long g originalWarningState = warning('off','fixed:fi:underflow'); originalFiprefState = get(fipref); reset(fipref)
Этот алгоритм нормирует данные без знака с 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) %#codegen 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
. Существует 0 битов начального нуля в 8-битном значении u=11111111_2
.
Таблица 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
Например, позволить
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 Start: u as unsigned integer.
Высоким байтом является 0 = 00000000_2
. Добавьте 1, чтобы сделать индекс из него: index = 0 + 1 = 1
. Количество интерполяционной таблицы начальных нулей в индексе 1 указывает, что существует 8 начальных нулей: NLZLUT(1) = 8
. Сдвиг влево этим много битов.
High byte Low byte 01001101 00000000 Left-shifted by 8 bits.
Выполните итерации еще раз, чтобы удалить начальные нули из следующего байта.
Высоким байтом является 77 = 01001101_2
. Добавьте 1, чтобы сделать индекс из него: index = 77 + 1 = 78
. Количество интерполяционной таблицы начальных нулей в индексе 78 указывает, что существует 1 начальный нуль: NLZLUT(78) = 1
. Сдвиг влево этим много битов.
High byte Low byte 100110100 0000000 Left-shifted by 1 additional bit, for a total of 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_x = bin(x)
binary_representation_of_u = '0000000001001101' binary_representation_of_x = '1001101000000000'
Очистка
Восстановите исходное состояние.
set(0, 'format', originalFormat); warning(originalWarningState); fipref(originalFiprefState); %#ok<*NOPTS>