首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何优化MATLAB的逐位运算

如何优化MATLAB的逐位运算
EN

Stack Overflow用户
提问于 2012-07-14 17:15:41
回答 2查看 5.3K关注 0票数 3

我用MATLAB写了我自己的SHA1实现,它给出了正确的哈希值。然而,它非常慢(在我的Corei7-2760QM上,一个1000 a的字符串需要9.9秒),我认为这种慢是MATLAB实现逐位逻辑运算(bitandbitorbitxorbitcmp)和整数的逐位移位(bitshiftbitrolbitror)的结果。

特别是我想知道是否需要使用fi命令为bitrolbitror构造定点数值对象,因为无论如何,在英特尔x86汇编中,都有用于各种大小的寄存器和内存地址的rolror。然而,bitshift非常快(它不需要任何定点数值构造物,一个常规的uint64变量就可以了),这使得情况变得更加奇怪:为什么在MATLAB中bitrolbitror需要用fi构造的定点数值对象,而bitshift不需要,在汇编级,这一切都归结为shlshrrolror

因此,在用C/C++将此函数编写为.mex文件之前,我很想知道是否有任何方法可以提高此函数的性能。我知道有一些针对SHA1的特定优化,但这不是问题所在,如果按位旋转的最基本实现如此缓慢。

使用tictoc进行了一些测试,很明显,导致它变慢的原因是bitrolfi的循环。有两个这样的循环:

代码语言:javascript
复制
%# Define some variables.
FFFFFFFF = uint64(hex2dec('FFFFFFFF'));

%# constants: K(1), K(2), K(3), K(4).
K(1) = uint64(hex2dec('5A827999'));
K(2) = uint64(hex2dec('6ED9EBA1'));
K(3) = uint64(hex2dec('8F1BBCDC'));
K(4) = uint64(hex2dec('CA62C1D6'));

W = uint64(zeros(1, 80));

... some other code here ...

%# First slow loop begins here.

for index = 17:80
    W(index) = uint64(bitrol(fi(bitxor(bitxor(bitxor(W(index-3), W(index-8)), W(index-14)), W(index-16)), 0, 32, 0), 1));
end

%# First slow loop ends here.

H = sha1_handle_block_struct.H;

A = H(1);
B = H(2);
C = H(3);
D = H(4);
E = H(5);

%# Second slow loop begins here.

for index = 1:80
    rotatedA = uint64(bitrol(fi(A, 0, 32, 0), 5));

    if (index <= 20)
        % alternative #1.
        xorPart = bitxor(D, (bitand(B, (bitxor(C, D)))));
        xorPart = bitand(xorPart, FFFFFFFF);
        temp = rotatedA + xorPart + E + W(index) + K(1);
    elseif ((index >= 21) && (index <= 40))
        % FIPS.
        xorPart = bitxor(bitxor(B, C), D);
        xorPart = bitand(xorPart, FFFFFFFF);
        temp = rotatedA + xorPart + E + W(index) + K(2);
    elseif ((index >= 41) && (index <= 60))
        % alternative #2.
        xorPart = bitor(bitand(B, C), bitand(D, bitxor(B, C)));
        xorPart = bitand(xorPart, FFFFFFFF);
        temp = rotatedA + xorPart + E + W(index) + K(3);
    elseif ((index >= 61) && (index <= 80))
        % FIPS.
        xorPart = bitxor(bitxor(B, C), D);
        xorPart = bitand(xorPart, FFFFFFFF);
        temp = rotatedA + xorPart + E + W(index) + K(4);
    else
        error('error in the code of sha1_handle_block.m!');
    end

temp = bitand(temp, FFFFFFFF);
E = D;
D = C;
C = uint64(bitrol(fi(B, 0, 32, 0), 30));
B = A;
A = temp;
end

%# Second slow loop ends here.

使用tictoc进行测量,在我的笔记本电脑上,message abc的SHA1散列的整个计算大约需要0.63秒,其中大约0.23秒在第一个慢循环中通过,在第二个慢循环中大约0.38秒。那么,在编写.mex文件之前,有什么方法可以在MATLAB中优化这些循环吗?

EN

回答 2

Stack Overflow用户

发布于 2012-07-14 17:43:53

为什么MATLAB中的bitrol和bitror需要用fi构造的定点数值对象,而bitshift不需要

bitrol和bitror不是适用于uint的位逻辑函数集的一部分。它们是定点工具箱的一部分,该工具箱还包含适用于定点输入的bitand、bitshift等变体。

如果您只想使用uint函数,则可以将bitrol表示为两个位移位,一个位数和一个位数。不过,这可能会更慢。

票数 3
EN

Stack Overflow用户

发布于 2012-07-15 00:14:46

与大多数MATLAB函数一样,bitandbitorbitxor都是矢量化的。所以如果你给这些函数向量输入,而不是在每个元素上循环调用它们,你会得到更快的速度

示例:

代码语言:javascript
复制
%# create two sets of 10k random numbers
num = 10000;
hex = '0123456789ABCDEF';
A = uint64(hex2dec( hex(randi(16, [num 16])) ));
B = uint64(hex2dec( hex(randi(16, [num 16])) ));

%# compare loop vs. vectorized call
tic
C1 = zeros(size(A), class(A));
for i=1:numel(A)
    C1(i) = bitxor(A(i),B(i));
end
toc

tic
C2 = bitxor(A,B);
toc

assert(isequal(C1,C2))

时间安排是:

代码语言:javascript
复制
Elapsed time is 0.139034 seconds.
Elapsed time is 0.000960 seconds.

这比以前快了一个数量级!

问题是,据我所知,SHA-1计算不能很好地向量化。因此,您可能无法利用这种矢量化。

作为实验,我实现了一个纯基于MATLAB的函数来计算这样的位操作:

代码语言:javascript
复制
function num = my_bitops(op,A,B)
    %# operation to perform: not, and, or, xor
    if ischar(op)
        op = str2func(op);
    end

    %# integer class: uint8, uint16, uint32, uint64
    clss = class(A);
    depth = str2double(clss(5:end));

    %# bit exponents
    e = 2.^(depth-1:-1:0);

    %# convert to binary
    b1 = logical(dec2bin(A,depth)-'0');
    if nargin == 3
        b2 = logical(dec2bin(B,depth)-'0');
    end

    %# perform binary operation
    if nargin < 3
        num = op(b1);
    else
        num = op(b1,b2);
    end

    %# convert back to integer
    num = sum(bsxfun(@times, cast(num,clss), cast(e,clss)), 2, 'native');
end

不幸的是,这在性能方面甚至更糟:

代码语言:javascript
复制
tic, C1 = bitxor(A,B); toc
tic, C2 = my_bitops('xor',A,B); toc
assert(isequal(C1,C2))

时间安排是:

代码语言:javascript
复制
Elapsed time is 0.000984 seconds.
Elapsed time is 0.485692 seconds.

结论:编写一个MEX函数或搜索文件交换,看看是否有人已经这样做了:)

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11482505

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档