Giả sử tôi muốn nhân mỗi phần tử của mảng ô A
với hệ số k
có hệ số. Tôi có thể làm điều đó bằng cách:Cách nhanh nhất để thực hiện các phép tính số học trên mỗi phần tử của một mảng ô là gì?
A = cellfun(@(x) k*x, A, 'UniformOutput', false)
Nhưng điều này cực kỳ chậm. Có cách nào nhanh hơn và tốt hơn không? Các phần tử mảng ô là các vectơ có chiều dài thay đổi, vì vậy cell2num
không áp dụng.
Chỉnh sửa: Dựa trên đề xuất của fpe's đề xuất cho vòng lặp for, đây là điểm chuẩn mẫu. Bắt đầu với dữ liệu này
A = arrayfun(@(n) rand(n,1), randi(5,1000,1000), 'UniformOutput',false);
Cuộc gọi cellfun
trên diễn 9.45 seconds
, trong khi một vòng lặp for:
A2 = cell(size(A));
for i = 1:size(A,1), for j = 1:size(A,2), A2{i,j} = A{i,j}*k; end; end
A = A2;
mất 1.67 seconds
, đó là một sự cải thiện đáng kể. Tôi vẫn muốn cái gì đó có một vài đơn đặt hàng của cường độ nhanh hơn. (Tôi cũng không hiểu lý do tại sao trình thông dịch Matlab không thể thực hiện cuộc gọi cellfun nhanh như vòng lặp. Chúng giống hệt nhau về mặt ngữ nghĩa.)
Chỉnh sửa 2: Đề xuất của Amro để tạo thành một vòng lặp là đáng kể nhanh hơn:
for i = 1:numel(A), A{i} = A{i}*k; end
mất 1.11 seconds
, và nếu tôi chạy pack
trước khi nó để sắp xếp bộ nhớ chỉ 0.88 seconds
.
Thực hiện chức năng MEX để thực hiện điều này thực sự không tốt hơn nhiều: 0.73 seconds
, (0.53 seconds
sau pack
), cho biết phân bổ nhiều ma trận nhỏ chậm trong Matlab.
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
if (nrhs != 2)
mexErrMsgTxt("need 2 arguments (Cell, Coefficient)");
mwSize const* size = mxGetDimensions(prhs[0]);
int N = mxGetNumberOfDimensions(prhs[0]);
if (mxGetNumberOfElements(prhs[1]) != 1)
mexErrMsgTxt("second argument to multcell must be a scalar");
double coefficient = *mxGetPr(prhs[1]);
plhs[0] = mxCreateCellArray(N, size);
int M = mxGetNumberOfElements(prhs[0]);
for (int i = 0; i < M; i++) {
mxArray *r = mxGetCell(prhs[0], i);
mxArray *l = mxCreateNumericArray(mxGetNumberOfDimensions(r),
mxGetDimensions(r),
mxDOUBLE_CLASS,
mxREAL);
double *rp = mxGetPr(r);
double *lp = mxGetPr(l);
int num_elements = mxGetNumberOfElements(r);
for (int i = 0; i < num_elements; i++)
lp[i] = rp[i] * coefficient;
mxSetCell(plhs[0], i, l);
}
}
Gian lận một chút, tuy nhiên, và thực hiện một chức năng MEX mà thực sự chỉnh sửa bộ nhớ tại chỗ có vẻ là cách duy nhất để có được hiệu suất hợp lý ra các hoạt động: 0.030 seconds
. Điều này sử dụng mxUnshareArray
không có giấy tờ theo đề xuất của Amro.
#include "mex.h"
extern "C" bool mxUnshareArray(mxArray *array_ptr, bool noDeepCopy);
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
if (nrhs != 2)
mexErrMsgTxt("need 2 arguments (Cell, Coefficient)");
mwSize const* size = mxGetDimensions(prhs[0]);
int N = mxGetNumberOfDimensions(prhs[0]);
if (mxGetNumberOfElements(prhs[1]) != 1)
mexErrMsgTxt("second argument to multcell must be a scalar");
double coefficient = *mxGetPr(prhs[1]);
mxUnshareArray(const_cast<mxArray *>(prhs[0]), false);
plhs[0] = const_cast<mxArray *>(prhs[0]);
int M = mxGetNumberOfElements(prhs[0]);
for (int i = 0; i < M; i++) {
mxArray *r = mxGetCell(prhs[0], i);
double *rp = mxGetPr(r);
int num_elements = mxGetNumberOfElements(r);
for (int i = 0; i < num_elements; i++)
rp[i] = rp[i] * coefficient;
}
}
trong bản phát hành MATLAB mới nhất, vòng lặp 'for' nói chung là giải pháp dễ nhất và nhanh nhất. – fpe
cảm ơn bạn, vòng lặp for thực sự nhanh hơn đáng kể (mặc dù vẫn rất chậm) – digitalvision
digitalvision: tại sao bạn nói nó cực kỳ chậm? chúng ta đang nói về kích thước nào, và nó hiện đang dùng bao lâu (tic/toc)? Tôi nghi ngờ một hoạt động như vậy là nút cổ chai trong mã của bạn ... Chạy hồ sơ và cố gắng tối ưu hóa các điểm nóng thực tế khác .. – Amro