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