簡體   English   中英

內存布局:2D N * M數據作為指向N * M緩沖區的指針或作為N個指向數組的指針的數組

[英]Memory layout : 2D N*M data as pointer to N*M buffer or as array of N pointers to arrays

我正在猶豫如何組織2D數據的內存布局。 基本上,我想要的是N * M 2D double精度數組,其中N〜M數以千計(並且是從用戶提供的數據派生的)

我看到的方式有2種選擇:

double *data = new double[N*M];

要么

double **data = new double*[N];
for (size_t i = 0; i < N; ++i)
     data[i] = new double[M];

首選是我所追求的。 我看到的主要優點是:較短的新/刪除語法,連續的內存布局(如果我正確安排訪問權限的話)意味着在運行時對相鄰內存的訪問,以及矢量化代碼(自動矢量化或使用矢量庫,例如vDSP或vecLib)的性能可能更高

另一方面,與分配一堆較小的連續內存相比,在我看來分配大塊連續內存可能會失敗/花費更多時間。 第二種方法的優勢還在於,與data[i*M+j]相比,語法data[i][j]較短

什么是最常見/更好的方法,主要是如果我嘗試從性能的角度來看它(即使這些改進很小,但我很想知道哪種性能更好)。

在前兩個選擇之間,對於MN合理值,我幾乎可以肯定會選擇第一個選擇。跳過指針取消引用,如果以正確的順序訪問數據,則可以得到很好的緩存。

考慮到您對尺寸的擔心,我們可以做一些后台計算。

由於MN為數千,因此假定每個上限為10000 那么您消耗的總內存為

 10000 * 10000 * sizeof(double) = 8 * 10^8

這大約是800 MB,雖然很大,但考慮到現代機器中的內存大小,這是相當合理的。

如果NM是常量,最好將所需的內存靜態聲明為二維數組。 或者,您可以使用std::array

std::array<std::array<double, M>, N> data;

如果只有M是一個常數,則可以使用std::arraystd::vector代替。

std::vector<std::array<double, M>> data(N);

如果M不是常數,則需要執行一些動態分配。 但是, std::vector可用於為您管理該內存,因此您可以圍繞它創建一個簡單的包裝器。 下面的包裝返回一個row中間對象,以允許second []運算符實際將偏移量計算到vector

template <typename T>
class matrix {
    const size_t N;
    const size_t M;
    std::vector<T> v_;
    struct row {
        matrix &m_;
        const size_t r_;
        row (matrix &m, size_t r) : m_(m), r_(r) {}
        T & operator [] (size_t c) { return m_.v_[r_ * m_.M + c]; }
        T operator [] (size_t c) const { return m_.v_[r_ * m_.M + c]; }
    };
public:
    matrix (size_t n, size_t m) : N(n), M(m), v_(N*M) {}
    row operator [] (size_t r) { return row(*this, r); }
    const row & operator [] (size_t r) const { return row(*this, r); }
};


matrix<double> data(10,20);
data[1][2] = .5;
std::cout << data[1][2] << '\n';

解決您對性能的特別關注時:希望進行單個內存訪問的理由是正確的。 但是,您應該避免執行newdelete自己(這是該包裝程序提供的功能),並且如果將數據更自然地解釋為多維,那么在代碼中顯示出來也將使代碼也更易於閱讀。

第二種方法所示的多重分配較差,因為它會花費更多時間,但是其優點是,如果您的系統碎片化,則分配可能會更成功(空閑內存由較小的孔組成,並且您沒有空閑的內存塊)足以滿足單個分配請求的內存)。 但是多重分配還有另一個缺點,那就是需要更多的內存來為指向每一行的指針分配空間。

我的建議是提供單一分配技術,而無需顯式調用newdelete ,因為內存是由vector管理的。 同時,它允許使用二維語法[x][y]尋址數據。 因此,只要您有足夠的內存來滿足分配請求,它就可以提供單一分配的所有好處以及多重分配的所有好處。

考慮使用類似以下的內容:

// array of pointers to doubles to point the beginning of rows
double ** data = new double*[N];

// allocate so many doubles to the first row, that it is long enough to feed them all
data[0] = new double[N * M];

// distribute pointers to individual rows as well
for (size_t i = 1; i < N; i++)
    data[i] = data[0] + i * M;

我不確定這是否是通用做法,我只是想出了這一點。 這種方法仍然存在一些缺點,但是我認為它消除了大多數方法,例如能夠訪問data[i][j]等所有雙精度數。

查找m * m(2 &lt;= m

[英]Find a subarray of m*m (2<=m<n) having largest sum; out of an n*n int array(having +ve, -ve, 0s)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM