2010-07-30 47 views
21

Câu hỏi khá ngu ngốc, nhưng tôi cần phải làm điều đó một cách rất hiệu quả - nó sẽ được thực hiện lặp đi lặp lại trong mã của tôi. Tôi có một hàm trả về một vectơ và tôi phải thêm các giá trị trả về cho một vectơ khác, phần tử theo phần tử. Khá đơn giản:Cách thêm phần tử theo yếu tố của hai vectơ STL?

vector<double> result; 
vector<double> result_temp 
for(int i=0; i< 10; i++) result_temp.push_back(i); 

result += result_temp //I would like to do something like that. 
for(int i =0; i< result_temp.size();i++)result[i] += result_temp[i]; //this give me segfault 

Phép toán mà tôi đang cố gắng để làm là

u [i] = u [i] + v [i] với mọi i

Có thể làm gì ?

Cảm ơn

EDIT: thêm khởi tạo đơn giản, vì đó không phải là điểm. Kết quả sẽ được khởi tạo như thế nào?

+5

Bạn có đăng một số mã compilable? "Điều này mang lại cho tôi một segfault" không phải là đặc biệt hữu ích mà không nhìn thấy cách những vectơ được khởi tạo. Vấn đề rất có thể là một trong các vectơ dài hơn vectơ kia. Rất khó để biết mã của bạn ở đâu sai mà không thấy tất cả mã :-) –

+0

http://www.boost.org/doc/libs/1_43_0/libs/numeric/ublas/doc/operations_overview.htm – Anycorn

Trả lời

28

Nếu bạn đang cố gắng nối thêm một số vector cho người khác, bạn có thể sử dụng một cái gì đó như sau. Đây là những từ một trong những tiện ích thư viện của tôi - hai operator+= quá tải cho std::vector: một gắn thêm một yếu tố duy nhất để các vector, khác gắn toàn bộ vector:

template <typename T> 
std::vector<T>& operator+=(std::vector<T>& a, const std::vector<T>& b) 
{ 
    a.insert(a.end(), b.begin(), b.end()); 
    return a; 
} 

template <typename T> 
std::vector<T>& operator+=(std::vector<T>& aVector, const T& aObject) 
{ 
    aVector.push_back(aObject); 
    return aVector; 
} 

Nếu bạn đang cố gắng để thực hiện một tổng (có nghĩa là , tạo ra một mới vector chứa số tiền của các yếu tố của hai vector s khác), bạn có thể sử dụng giống như sau:

#include <algorithm> 
#include <functional> 

template <typename T> 
std::vector<T> operator+(const std::vector<T>& a, const std::vector<T>& b) 
{ 
    assert(a.size() == b.size()); 

    std::vector<T> result; 
    result.reserve(a.size()); 

    std::transform(a.begin(), a.end(), b.begin(), 
        std::back_inserter(result), std::plus<T>()); 
    return result; 
} 

bạn tương tự có thể thực hiện một tình trạng quá tải operator+=.

+0

Xin cảm ơn, nhưng tôi không cố gắng thêm một giá trị vào cuối vectơ, tôi đang cố tổng hợp giá trị hiện tại của các phần tử vectơ với các giá trị của một vectơ khác. Kích thước của vectơ luôn được cố định. – Ivan

+2

@Ivan: Xem bản chỉnh sửa; Tôi đã không hoàn toàn chắc chắn những gì bạn đang tìm kiếm cho đến khi tôi nhìn thấy bình luận của bạn trong trả lời cho câu trả lời của Greg. –

+2

@James Bỏ qua nhận xét ban đầu của tôi - bây giờ bạn đã có mã ưa thích và có liên quan :) –

0

Tôi có @James McNellis - mã này có vẻ chính xác, miễn là resultresult_temp có cùng độ dài.

Ngoài ra - tại sao bạn khai báo result, nhưng sử dụng biến result_v - đó là cách mã thực sự được viết? Nếu vậy, đó là vấn đề

1

Bạn cần khởi tạo result cho tất cả các số 0 trước; chỉ tuyên bố biến không thực sự phân bổ bất kỳ phần tử nào.

Hãy thử điều này:

vector<double> result(10); // default-initialize to 10 elements 
vector<double> result_temp; 
for(int i=0; i< 10; i++) 
    result_temp.push_back(i); 

for(int i =0; i< result_temp.size();i++) 
    result[i] += result_temp[i]; 
0

Mã này có vẻ tốt đẹp, nhưng nghiêng đầu tiên của tôi sẽ được thay đổi bất cứ điều gì đang điền vào vector với các giá trị để thêm vào các giá trị trong các vector đầu tiên để có trong một tham chiếu đến vector đầu tiên và thêm trực tiếp vào nó thay vì tạo một vectơ mới được trả về. Điều đó không hiệu quả.

Nếu bạn không thể thay đổi hàm theo cách đó, có lẽ bạn có thể thay đổi nó để tham chiếu đến vectơ mà nó xóa và sau đó chèn các giá trị vào để bạn không sao chép vectơ xung quanh. Điều đó có thể trở nên đắt đỏ nếu bạn làm nhiều.

Một nitpick khác nếu bạn đang cố gắng để có được điều này càng nhanh càng tốt, bạn nên sử dụng tiền gia tăng với vòng lặp thay vì tăng sau. Việc tạo tạm thời sau khi tăng không thể được tối ưu hóa khi xử lý các toán tử quá tải thay vì các kiểu dựng sẵn. Vì vậy, bạn tiếp tục tạo và phá hủy tạm thời mọi lần lặp của vòng lặp của bạn.EDIT: Như đã được chỉ ra trong các ý kiến, bạn đang sử dụng các chỉ số ở đây chứ không phải là vòng lặp (tôi rõ ràng là không chú ý đủ), vì vậy lời khuyên này không thực sự áp dụng ở đây. Tuy nhiên, trong trường hợp bạn bằng cách sử dụng trình vòng lặp, nó vẫn hợp lệ.

Ngoài ra, nếu bạn đang cố gắng để thêm tất cả các yếu tố của hai véc tơ togther, những gì bạn có có lẽ là về một giải pháp hiệu quả như bạn sẽ nhận được. Có những cách tốt hơn nếu những gì bạn quan tâm là chèn các phần tử của một véc tơ vào một véc tơ khác, nhưng nếu bạn chỉ cần thêm các giá trị của chúng lại với nhau, thì những gì bạn có vẻ tốt. Tôi hy vọng rằng bằng cách sử dụng bất kỳ thuật toán STL sẽ là tốt nhất chỉ là nhanh và có khả năng chậm hơn do các cuộc gọi chức năng bổ sung, nhưng bạn có thể phải cấu hình nó để chắc chắn.

+1

"bạn nên sử dụng tiền gia tăng với vòng lặp thay vì tăng sau". Đúng, nhưng anh ta không sử dụng các trình vòng lặp, anh ấy đang sử dụng một chỉ số nguyên. Khó khăn để thực hiện một trường hợp hiệu suất giữa trước và sau tăng cho rằng ;-) –

+0

Ah, tốt bắt. Tôi không chú ý đủ. Tôi hiếm khi sử dụng các chỉ số hơn là các vòng lặp và phản ứng ruột của tôi sau khi tăng là rất tiêu cực. Tôi là một người tin tưởng vững chắc luôn sử dụng tiền gia tăng trừ khi bạn cần tăng thêm tiền. Bằng cách đó, bạn không bao giờ phải lo lắng về việc liệu tạm thời sẽ được tối ưu hóa đi. Tuy nhiên, nó là chắc chắn đúng trong trường hợp này trình biên dịch nên không có vấn đề tối ưu hóa nó đi và sau tăng sẽ chỉ là hiệu quả như tiền gia tăng. –

+0

Vâng, thậm chí ngoài các vấn đề về hiệu năng có thể tôi cũng thích tăng trước, nhưng vì lý do gây tranh cãi mà tôi nghĩ nó rõ ràng và dễ đọc hơn. "Increment i" được viết, "++ i". Rất ít đồng ý. –

25

Có vẻ như sự cố đang truy cập các giá trị của result không tồn tại. tzaman cho thấy làm thế nào để khởi tạo kết quả đến 10 yếu tố, mỗi giá trị 0.

Bây giờ bạn cần phải gọi transform chức năng (từ < thuật toán >), áp dụng đối tượng plus chức năng (từ < chức năng >):

std::transform(result.begin(), result.end(), result_temp.begin(), 
       result.begin(), std::plus<double>()); 

Điều này lặp lại qua resultresult_temp, áp dụng plus làm tăng gấp đôi số tiền và ghi tổng số tiền đó trở lại result.

0

Nếu mã của bạn là segfaulting thì đó là vấn đề chính xác chứ không phải vấn đề về hiệu quả.

Để đạt được "u [i] = u [i] + v [i] với mọi i", tôi sẽ làm cơ bản những gì bạn đã làm:

assert(u.size() == v.size()); // will fail with your initialization code, since 
           // your "result" has size 0, not size 10. 
           // perhaps do u.resize(v.size()); 
for (size_t i = 0; i < u.size(); ++i) { 
    u[i] += v[i]; 
} 

Nếu bạn thực sự quan tâm đến hoạt động của chương trình của bạn (nghĩa là, bạn đã viết một phiên bản cơ bản và chương trình của bạn bị chậm một số yêu cầu và bạn đã chứng minh rằng đây là mã mà phần lớn thời gian được sử dụng), sau đó bạn có thể thử:

  • chuyển đổi trên nhiều tối ưu hóa trong trình biên dịch của bạn (thực ra, tôi thường làm điều này theo mặc định ngay cả khi không có vấn đề về hiệu năng),
  • sử dụng vòng lặp thay vì chỉ mục (hiếm khi tạo ra sự khác biệt nhiều, nhưng thật dễ dàng để so sánh hai),
  • bỏ vòng lặp một chút (có thể tạo ra sự chênh lệch tốc độ đáng giá, nhưng điều đó khá nhạy cảm với trường hợp cụ thể và nó khuyến khích các lỗi mã hóa).
  • xem hướng dẫn SIMD dành riêng cho nền tảng thay vì C++. Sau đó, sử dụng trình biên dịch nhúng hoặc trình biên dịch nội tại cho các hướng dẫn đó.

Tuy nhiên, bạn không phải lo lắng về hiệu suất trước khi mã của bạn chính xác ;-). "Làm cho nó hoạt động, làm cho nó đúng, làm cho nó nhanh" là một phương châm hợp lý, mặc dù thường bạn không cần phải đi xa như bước 3.

std::valarray thực sự có chính xác operator+= bạn muốn. Trước khi bạn thay thế tất cả các vectơ của mình bằng các valaray, hãy lưu ý rằng không nhất thiết có nghĩa là nó "hiệu quả hơn" so với một vòng lặp đơn giản - Tôi không biết những người thực hiện nghiêm túc mất valarray như thế nào. Bạn luôn có thể xem xét nguồn trong triển khai của mình.Tôi cũng không biết tại sao chức năng số học nhiều dữ liệu của valarray không được định nghĩa là một phần của vector, nhưng thường có một lý do.

+0

Giống như phương châm. – Vincent

6

Một ví dụ cụ thể của câu trả lời Jon Reid:

std::array<double,3> a = {1, 2, 3}; 
std::array<double,3> b = {4, 5, 6}; 
std::transform(a.begin(), a.end(), b.begin(), a.begin(),std::plus<double>()); 
ASSERT_TRUE(a[0] == 5); 
ASSERT_TRUE(a[1] == 7); 
ASSERT_TRUE(a[2] == 9); 
Các vấn đề liên quan