我目前正在爲C++編寫一個linalg庫,用於教育目的和個人使用。作爲它的一部分,我使用自定義行和列迭代器實現了一個自定義矩陣類。雖然提供了使用std :: algorithm和std :: numeric函數的非常好的功能,但我在索引和iterator/std :: inner_product方法之間執行了矩陣乘法的速度比較。結果顯著不同:C++速度比較迭代器與索引
// used later on for the custom iterator
template<class U>
struct EveryNth {
bool operator()(const U&) { return m_count++ % N == 0; }
EveryNth(std::size_t i) : m_count(0), N(i) {}
EveryNth(const EveryNth& element) : m_count(0), N(element.N) {}
private:
int m_count;
std::size_t N;
};
template<class T,
std::size_t rowsize,
std::size_t colsize>
class Matrix
{
private:
// Data is stored in a MVector, a modified std::vector
MVector<T> matrix;
std::size_t row_dim;
std::size_t column_dim;
public:
// other constructors, this one is for matrix in the computation
explicit Matrix(MVector<T>&& s): matrix(s),
row_dim(rowsize),
column_dim(colsize){
}
// other code...
typedef boost::filter_iterator<EveryNth<T>,
typename std::vector<T>::iterator> FilterIter;
// returns an iterator that skips elements in a range
// if "to" is to be specified, then from has to be set to a value
// @ param "j" - j'th column to be requested
// @ param "from" - starts at the from'th element
// @ param "to" - goes from the from'th element to the "to'th" element
FilterIter begin_col(std::size_t j,
std::size_t from = 0,
std::size_t to = rowsize){
return boost::make_filter_iterator<EveryNth<T> >(
EveryNth<T>(cols()),
matrix.Begin() + index(from, j),
matrix.Begin() + index(to, j)
);
}
// specifies then end of the iterator
// so that the iterator can not "jump" past the last element into undefines behaviour
FilterIter end_col(std::size_t j,
std::size_t to = rowsize){
return boost::make_filter_iterator<EveryNth<T> >(
EveryNth<T>(cols()),
matrix.Begin() + index(to, j),
matrix.Begin() + index(to, j)
);
}
FilterIter begin_row(std::size_t i,
std::size_t from = 0,
std::size_t to = colsize){
return boost::make_filter_iterator<EveryNth<T> >(
EveryNth<T>(1),
matrix.Begin() + index(i, from),
matrix.Begin() + index(i, to)
);
}
FilterIter end_row(std::size_t i,
std::size_t to = colsize){
return boost::make_filter_iterator<EveryNth<T> >(
EveryNth<T>(1),
matrix.Begin() + index(i, to),
matrix.Begin() + index(i, to)
);
}
// other code...
// allows to access an element of the matrix by index expressed
// in terms of rows and columns
// @ param "r" - r'th row of the matrix
// @ param "c" - c'th column of the matrix
std::size_t index(std::size_t r, std::size_t c) const {
return r*cols()+c;
}
// brackets operator
// return an elements stored in the matrix
// @ param "r" - r'th row in the matrix
// @ param "c" - c'th column in the matrix
T& operator()(std::size_t r, std::size_t c) {
assert(r < rows() && c < matrix.size()/rows());
return matrix[index(r,c)];
}
const T& operator()(std::size_t r, std::size_t c) const {
assert(r < rows() && c < matrix.size()/rows());
return matrix[index(r,c)];
}
// other code...
// end of class
};
現在在運行的主要功能如下:
int main(int argc, char *argv[]){
Matrix<int, 100, 100> a = Matrix<int, 100, 100>(range<int>(10000));
std::clock_t begin = clock();
double b = 0;
for(std::size_t i = 0; i < a.rows(); i++){
for (std::size_t j = 0; j < a.cols(); j++) {
std::inner_product(a.begin_row(i), a.end_row(i),
a.begin_column(j),0);
}
}
// double b = 0;
// for(std::size_t i = 0; i < a.rows(); i++){
// for (std::size_t j = 0; j < a.cols(); j++) {
// for (std::size_t k = 0; k < a.rows(); k++) {
// b += a(i,k)*a(k,j);
// }
// }
// }
std::clock_t end = clock();
double elapsed_secs = double(end - begin)/CLOCKS_PER_SEC;
std::cout << elapsed_secs << std::endl;
std::cout << "--- End of test ---" << std::endl;
std::cout << std::endl;
return 0;
}
對於性病:: inner_product /迭代器,它需要的方法:
bash-3.2$ ./main
3.78358
--- End of test ---
和索引(// out)方法:
bash-3.2$ ./main
0.106173
--- End of test ---
這比迭代器方法快了近40倍。你看到代碼中的任何東西都會減慢迭代器計算的速度嗎?我應該提及的是,我嘗試了兩種方法,併產生了正確的結果。
謝謝你的想法。
它可能屬於代碼審查......你也應該補充你的編譯器,以及所有編譯器選項。 – quantdev 2014-10-11 12:17:21
看起來你並沒有使用你的迭代器迭代,而是每次都創建新的迭代器。或者我讀錯了嗎? – Galik 2014-10-11 12:21:25
@Galik:更新了帖子。複製時發生錯誤。 – Vincent 2014-10-11 12:31:55