Умножение двоичных векторов - PullRequest
1 голос
/ 10 апреля 2019

Я проектирую множитель в MATLAB, но не знаю, как выполнить умножение двоичных чисел. Например, я хочу умножить двоичный 110011 на двоичный 0011. Но MATLAB дает ошибку матричного измерения. Кроме того, если я добавлю нули в MSB с меньшим номером элемента, это все равно не позволит мне умножить. Есть какой-то конкретный алгоритм, который мне не хватает?

Я не хочу делать побитовое И. Мне нужно выполнить правильное умножение как

          1 1 0 0 1 1
              0 0 1 1

          1 1 0 0 1 1
        1 1 0 0 1 1
      0 0 0 0 0 0
  0 0 0 0 0 0

  0 0 1 0 0 1 1 0 0 1

вот фрагмент кода, где я добавляю нули.

if numel(operand1)<numel(operand2)
append=zeros(1, (numel(operand2)-numel(operand1)));
operand1=[operand1 append];
else
append=zeros(1, (numel(operand1)-numel(operand2)));
operand2=[operand2 append];
end    

(PS: извините за плохую читабельность, это мой самый первый пост о stackoverflow, я не очень разбираюсь в форматировании)

1 Ответ

1 голос
/ 11 апреля 2019

Это только одна из многих возможных реализаций.Он не должен быть самым быстрым и ярким.Он также может быть сильно укорочен, но для того, чтобы показать промежуточные шаги, я оставил его довольно развернутым.

Шаг 1: подготовить все шаги (строки)

Вместо этогонеобходимости управлять добавлением нулей здесь или там, в зависимости от длины каждого входа, я считаю более простым просто определить матрицу, достаточно большую, чтобы вместить все наши значения и циклические сдвиги, которые мы должны будем выполнить:

%% Input values
a = [ 1 1 0 0 1 1 ] ;
b = [     1 0 1 1 ] ;

%% create all the steps
nstep = numel(b) ;
steps = bsxfun( @times , flipud(b.') , a) ;

На этом этапе ваша матрица steps выглядит следующим образом:

>> steps
steps =
     1     1     0     0     1     1
     1     1     0     0     1     1
     0     0     0     0     0     0
     1     1     0     0     1     1

Каждая строка представляет полный вектор a, умноженный на каждый элемент b Прежде чем мы сможем суммировать эти строки, нам нужносдвинуть каждую строку так, чтобы она выровнялась с правильной степенью 2. Для этого мы сначала дополним матрицу необходимыми нулями слева, а затем будем использовать circshift:

%% pad the matrix to prepare for the shifts
pad = zeros( nstep , nstep ) ;
mat = [pad steps] ;

%% shift the step lines
for k=2:nstep
    mat(k,:) = circshift(mat(k,:),[0,-(k-1)]) ; % shift each line to the left by [k-1]
end

К настоящему времени ваша матрица mat выглядит следующим образом:

>> mat
mat =
     0     0     0     0     1     1     0     0     1     1
     0     0     0     1     1     0     0     1     1     0
     0     0     0     0     0     0     0     0     0     0
     0     1     1     0     0     1     1     0     0     0

Почти там, теперь нам просто нужно сложить строки, чтобы получить наш результат.К сожалению, MATLAB не имеет суммирования бинарного , построенного таким образом, поэтому нам придется реализовать его самостоятельно.Я дам 2 метода: loop версия (более читабельная) и векторизованная версия (более критично).

Шаг 2: Суммирование

%% [LOOP method] Do the summation
ncol = size(mat,2) ;
res  = zeros( 1 , ncol ) ;  % pre-allocate result line
sumline = sum(mat) ;        % put sum of each column in a buffer

c = 0 ; % carry
for k=ncol:-1:2             % we process the column from right to left
    s      = sumline(k)+c ; % sum of the column [k] plus the carry
    res(k) = mod( s , 2 ) ; % result for this column
    c = floor(s/2)        ; % carry value for the next column
end
% now we are almost finished but there may be value left in the carry
res(1) = c  % set the (MSb) on the left

Обратите внимание, что цикл останавливается на столбце 2 вместо столбца 1. Это потому, что я уже добавил еще один столбец слева, который будет содержать только нули.Это сделано для того, чтобы в переменной res было достаточно столбцов для размещения carry на случай, если оно не равно нулю.

Ниже приведена более компактная версия (из шага 2), но она будетдают точно такие же результаты:

%% [Vectorised method] ... just as good but more cryptic
sumline  = sum(mat) ;                                   % put sum of each column in a buffer
carrytmp = floor(sumline/2) ;                           % calculate all the "carry" values (1/2)
carry    = carrytmp + circshift( carrytmp, [0,-1] ) ;   % calculate all the "carry" values (2/2)
tsum     = sumline + circshift( carry , [0,-1] ) ;      % total sum
res      = mod( tsum , 2 ) ;                            % final result

Ну вот, извините за длинный пост, но я хотел подробно описать шаги.Если вы берете только код, вы можете сжать его в короткую функцию:

function res = binary_multiplication(a,b)

nstep = numel(b) ;
mat   = [zeros( nstep , nstep ) , bsxfun( @times , flipud(b.') , a) ] ;
for k=2:nstep
    mat(k,:) = circshift(mat(k,:),[0,-(k-1)]) ;
end
sumline  = sum(mat) ;
res      = mod(sumline+circshift(floor(sumline/2)+circshift(floor(sumline/2),[0,-1]),[0,-1]),2) ;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...