#matlab
#matlab
Вопрос:
Я разрабатываю множитель в 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. Можете ли вы показать, как вы добавляете нули, а затем умножаете?
2. Вам явно нужно визуализировать показанные шаги умножения?
3. Пожалуйста, добавьте свой код, чтобы мы могли проверить и дать вам правильный ответ.
4. Если вы хотите сделать это простым способом, преобразуйте двоичное представление в обычные целые числа, умножьте, затем преобразуйте обратно. Чтобы сделать это сложным способом, вам нужно реализовать логику по мере отображения, используя цикл for и
circshift
сдвинуть один из операндов.5. @rinkert вот мой фрагмент кода. если numel(операнд 11)добавить]; конец
Ответ №1:
Это всего лишь одна возможная реализация из многих. Он не должен быть самым быстрым и ярким. Его также можно было бы сильно сократить, но ради показа промежуточных шагов я оставил его довольно расширенным.
Шаг 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 метода: циклическую версию (более читаемую) и векторизованную версию (более критичную).
Шаг 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
переменная имела достаточно столбцов для размещения переноса в случае, если оно не равно null.
Ниже приведена более компактная версия (шага 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) ;