Cách hiệu quả nhất để viết các vòng lặp 'cho' trong Matlab là gì?


12

Tôi đã đọc rằng, ví dụ, nếu tôi có một forvòng lặp kép chạy qua các chỉ mục của ma trận, thì việc đặt cột chạy chỉ mục ở vòng lặp bên ngoài sẽ hiệu quả hơn. Ví dụ:

a=zeros(1000);
for j=1:1000
 for i=1:1000
  a(i,j)=1;
 end
end

Cách hiệu quả nhất để mã hóa nó là gì nếu tôi có ba forvòng lặp trở lên ?

Ví dụ:

a=zeros(100,100,100);
for j=1:100
 for i=1:100
  for k=1:100
   a(i,j,k)=1;
  end
 end
end

4
Forcác vòng lặp rất chậm trong MATLAB. Bạn nên tránh các vòng lặp rõ ràng trong MATLAB bất cứ khi nào có thể. Thay vào đó, thông thường một vấn đề có thể được thể hiện dưới dạng các phép toán ma trận / vectơ. Đó là cách MATLABic. Ngoài ra còn có rất nhiều hàm dựng sẵn để khởi tạo ma trận, v.v. Ví dụ, có một hàm, những cái () , sẽ đặt tất cả các phần tử của ma trận thành 1 (bằng cách mở rộng, thành bất kỳ giá trị nào bằng phép nhân (vô hướng nhân với ma trận tất cả những người)). Nó cũng hoạt động trên các mảng 3 chiều (mà tôi nghĩ bao gồm ví dụ ở đây).
Peter Mortensen

3
@PeterMortensen Theo yếu tố nào (đại khái) hiệu quả của các vòng lặp trong Matlab nhỏ hơn so với C và Python? Và tại sao vậy? Ngoài ra, hiệu quả của các vòng lặp trong Matlab không tốt hơn trong vài năm qua?
TensoR

3
@PeterMortensen Sinh thường là một vấn đề có thể được thể hiện dưới dạng các hoạt động ma trận / véc tơ - đối với một số giá trị nhất định của Thông thường, vâng. IMO chính xác hơn để nói rằng những người làm việc ở Matlab và những người tương tự có văn hóa kéo dài hàng thập kỷ bỏ qua tất cả những điều không thể thực hiện được với các hoạt động ma trận / vectơ, đến nỗi mọi thứ trông giống như một cái đinh đối với cây búa đó . Và chúng ta không nên nói rằng các vòng lặp trong Matlab là chậm, nhưng Matlab chậm chậm (nó chỉ được liên kết với một thư viện nhanh của các nguyên thủy LA được viết bằng C và Fortran).
rẽ trái

5
Hiệu suất của các vòng lặp đang gây tranh cãi: matlabtips.com/matlab-is-no-longer-slow-at-for-loops
ohreally

@leftaroundabout Đúng. Quan tâm đến tốc độ trong ngôn ngữ được dịch (hoặc bán phiên dịch) là một dấu hiệu khá rõ ràng bạn có vấn đề XY trong đó giải pháp thực tế là "không sử dụng ngôn ngữ này". Tất nhiên, ngoại lệ là nếu bạn đang sử dụng tạo mã trong Simulink, nhưng câu hỏi đặt ra là C tạo trình tạo mã nào và hiệu quả của nó như thế nào.
Graham

Câu trả lời:


18

Câu trả lời ngắn gọn, bạn muốn có chỉ số ngoài cùng bên trái trong vòng lặp trong cùng. Trong ví dụ của bạn, các chỉ số vòng lặp sẽ đi k, j, i và các chỉ số mảng sẽ là i, j, k. Điều này có liên quan đến cách MATLAB lưu trữ các kích thước khác nhau trong bộ nhớ. Để biết thêm, xem # 13 của bài đăng reddit này .


2
Hoặc sử dụng các hàm tích hợp () .
Peter Mortensen

5
Ví dụ của @Peter OP gần như chắc chắn chỉ là một ví dụ đồ chơi của vòng lặp for thực hiện điều gì đó chứ không phải trường hợp sử dụng thực tế.
Matt

@Matt Bạn đúng rồi.
TensoR

11

Một câu trả lời dài hơn một chút giải thích tại sao nó hiệu quả hơn khi có hầu hết các chỉ số bên trái thay đổi nhanh nhất. Có hai điều quan trọng mà bạn cần hiểu.

Đầu tiên, MATLAB (và Fortran, nhưng không phải C và hầu hết các ngôn ngữ lập trình khác) lưu trữ các mảng trong bộ nhớ theo "thứ tự chính của cột". ví dụ: nếu A là ma trận 2 nhân 3, thì các mục nhập sẽ được lưu trong bộ nhớ theo thứ tự

A (1,1,1)

A (2,1,1)

A (1,2,1)

A (2,2,1)

A (1,3,1)

A (2,3,1)

A (1,1,2)

A (2,1,2)

...

A (2,3,10)

Sự lựa chọn thứ tự chính của cột này là tùy ý - chúng ta có thể dễ dàng chấp nhận quy ước "thứ tự chính hàng" và trên thực tế đó là những gì được thực hiện trong C và một số ngôn ngữ lập trình khác.

Điều quan trọng thứ hai mà bạn cần hiểu là các bộ xử lý hiện đại không truy cập bộ nhớ một vị trí tại một thời điểm, mà tải và lưu trữ "các dòng bộ đệm" gồm 64 hoặc thậm chí 128 byte liền kề (8 hoặc 16 số dấu phẩy động chính xác kép) tại một thời điểm từ bộ nhớ. Các khối dữ liệu này được lưu trữ tạm thời trong bộ nhớ cache nhanh và ghi lại khi cần. (Trong thực tế, kiến ​​trúc bộ đệm hiện khá phức tạp với tối đa 3 hoặc 4 cấp bộ nhớ đệm, nhưng ý tưởng cơ bản có thể được giải thích bằng bộ đệm một cấp của loại máy tính có trong những ngày còn trẻ.)

Một

Nếu các vòng lặp được lồng nhau sao cho vòng lặp trong cùng cập nhật chỉ mục hàng, thì các mục mảng sẽ được truy cập theo thứ tự A (1,1), A (2.1), A (3,1), ... Khi mục đầu tiên A (1,1) được truy cập, hệ thống sẽ đưa một dòng bộ đệm chứa A (1,1), A (2.1), ..., A (8.1) vào bộ đệm từ bộ nhớ chính . 8 lần lặp tiếp theo của vòng lặp trong cùng hoạt động trên dữ liệu này mà không cần chuyển thêm bộ nhớ chính.

Nếu thay thế, chúng ta cấu trúc các vòng lặp để chỉ số cột thay đổi trong vòng lặp trong cùng, thì các mục nhập của A sẽ được truy cập theo thứ tự A (1,1), A (1,2), A (1,3 ), ... Trong trường hợp này, lần truy cập đầu tiên sẽ đưa A (1,1), A (2.1), ..., A (8.1) vào bộ nhớ cache từ bộ nhớ chính, nhưng 7/8 những mục này sẽ không được sử dụng. Việc truy cập vào A (1,2) trong lần lặp thứ hai sau đó sẽ mang lại 8 mục khác từ bộ nhớ chính, v.v. Vào thời điểm mã xung quanh hoạt động ở hàng 2 của ma trận, mục A (2.1) có thể bị xóa khỏi bộ đệm để nhường chỗ cho các dữ liệu cần thiết khác. Kết quả là, mã đang tạo ra lưu lượng truy cập gấp 8 lần khi cần thiết.

Một số trình biên dịch tối ưu hóa có khả năng tự động tái cấu trúc các vòng lặp để tránh vấn đề này.

Nhiều thuật toán đại số tuyến tính số cho phép nhân và nhân tử ma trận có thể được tối ưu hóa để hoạt động hiệu quả với sơ đồ đặt hàng chính hoặc cột chính tùy thuộc vào ngôn ngữ lập trình. Làm điều này sai cách có thể có tác động tiêu cực đáng kể đến hiệu suất.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.