複数のコンテナにて同じ要素番号の値を全て加算するアルゴリズム – プログラミング – Home

複数のコンテナにて同じ要素番号の値を全...
 
通知
すべてクリア

複数のコンテナにて同じ要素番号の値を全て加算するアルゴリズム


とほほ
 とほほ
(@とほほ)
ゲスト
結合: 17年前
投稿: 23
Topic starter  

いつもお世話になります。

複数のコンテナがあり各ベクトルの要素数は同じこととします。
各コンナの同じ要素番号の値を全て加算して他のコンテナに代入する。
STLでこのような動作を行うアルゴリズムは準備されていないでしょうか。
ご教示おねがいします。

#include <iostream>
#include <vector>

using namespace std;

int main() {

vector<int>lhs[3], rhs;

lhs[0].push_back(1); lhs[0].push_back(2); lhs[0].push_back
(3); lhs[0].push_back(4); lhs[0].push_back(5);
lhs[0].push_back(6); lhs[0].push_back(7); lhs[0].push_back
(8); lhs[0].push_back(9); lhs[0].push_back(10);

lhs[1].push_back(10); lhs[1].push_back(20); lhs[1].push_back
(30); lhs[1].push_back(40); lhs[1].push_back(50);
lhs[1].push_back(60); lhs[1].push_back(70); lhs[1].push_back
(80); lhs[1].push_back(90); lhs[1].push_back(100);

lhs[2].push_back(100); lhs[2].push_back(200); lhs[2].push_back
(300); lhs[2].push_back(400); lhs[2].push_back(500);
lhs[2].push_back(600); lhs[2].push_back(700); lhs[2].push_back
(800); lhs[2].push_back(900); lhs[2].push_back(1000);

vector<int>::iterator it, it1, it2;
it = lhs[0].begin(); it1 = lhs[1].begin();it2 = lhs[2].begin();

int result= 0;

while( it != lhs[0].end()) {
result = *it + *it1+ *it2;
rhs.push_back(result);
++it; ++it1; ++it2;
}

copy(rhs.begin(), rhs.end(), ostream_iterator<int>(cout, ));
return 0;
}

// VS2005 / STL


引用解決済
トピックタグ
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 22年前
投稿: 1301
 

あったとしてもふたつまで。


返信引用
とほほ
 とほほ
(@とほほ)
ゲスト
結合: 17年前
投稿: 23
Topic starter  

επιστημη さんいつもお世話になります。

インデントがガタガタですみません。
>あったとしてもふたつまで。
そうですか250×500以上のmatrixになるので無理ですね
lhs[n]型のvectorコンテナを宣言するのも250個イテレータを宣言するのも250個なので
テストコードをタイピングするのもあほらしいので秀丸マクロで書いたのですが
こんなのでいいのってな感じです。

「stl vector 行列演算」で検索するとεπιστημη さんのところの
過去ログがヒットし只今調査中しています雰囲気ではvalarray の
gsliceクラスが使えそうな感じなのですが私には敷居が高い感じです。
Lokiとかは無理ですがBoostなら使ったことがあるのでそれも視野に入れて探してみま
す。


返信引用
アキラ
 アキラ
(@アキラ)
ゲスト
結合: 23年前
投稿: 49
 

簡単ですけど、こうかな

template <class T, class OutputIterator>
void matrix_sum(const std::vector<std::vector<T> >& in, OutputIterator out)
{
size_t index = 0;
while (in.begin() + index != in.end()) {
T sum = T();
for (size_t i = 0; i < in.size(); ++i) {
sum += in[i][index];
}
*out = sum;
++out;

++index;
}
}

int main()
{
vector<vector<int> > lhs(3);
vector<int> rhs;

lhs[0].push_back(1);
lhs[0].push_back(2);
lhs[0].push_back(3);

lhs[1].push_back(4);
lhs[1].push_back(5);
lhs[1].push_back(6);

lhs[2].push_back(7);
lhs[2].push_back(8);
lhs[2].push_back(9);

matrix_sum(lhs, back_inserter(rhs));
copy(rhs.begin(), rhs.end(), ostream_iterator<int>(cout, \n));

return 0;
}


返信引用
アキラ
 アキラ
(@アキラ)
ゲスト
結合: 23年前
投稿: 49
 

もしくはこうかな
vector<vector<T> >しか想定してないですけど

template <class InputIterator, class OutputIterator>
void matrix_sum(InputIterator first, InputIterator last, OutputIterator out)
{
typedef iterator_traits<InputIterator>::value_type::value_type value_type;

size_t index = 0;
while (first + index != last) {
value_type sum = value_type();
for (InputIterator it = first; it != last; ++it) {
sum += (*it)[index];
}
*out = sum;
++out;

++index;
}
}

int main()
{
vector<vector<int> > lhs(3);
vector<int> rhs;

...

matrix_sum(lhs.begin(), lhs.end(), back_inserter(rhs));

return 0;
}


返信引用
tetrapod
 tetrapod
(@tetrapod)
ゲスト
結合: 21年前
投稿: 830
 

ソースコードの見た目も大事だが実行速度も大事なのであって
データキャッシュヒット率を考えてコード書く必要があるかもしんないよ

配列の各要素がメモリ上で連続するので、でかい配列が複数ある場合、
・同一配列に対する操作はキャッシュヒット率が高く
・異なる配列の同一インデックスに対する操作はキャッシュヒット率が低い
ことが容易に予想される

valarray sum, a1, a2 ...; があるとき

// 遅いことが予想される
for (i=0; i<sum.size(); ++i) {
 sum[i]=a1[i]+a2[i]+a3[i]+a4[i]+ ... ;
}

// こっちのほうが速いと思われる
sum.fill(0);
sum+=a1;
sum+=a2;
sum+=a3;

計測してないので真偽のほどはなんともいえないけどさ


返信引用
とほほ
 とほほ
(@とほほ)
ゲスト
結合: 17年前
投稿: 23
Topic starter  

アキラ さん、tetrapod さんお世話になります。

>tetrapod さん
なるほどたしかにおっしゃる通りだと思います。

>アキラ さん
夕べ考えすぎて眠れませんでしたといいますのは
アキラさんが書いてくれたコードを下記のようにうしてみたのですが
lhsの要素の数よりもnの数(個々の配列の要素数)が少ない場合テンプレート
void matrix_sum()関数が<vector>の中でこのように破綻してしまいます。
Debug Assertion Failed!

Program: ...
File: c:\program files\microsoft visual studio 8\vc\include\vector
Line: 741

Expression: vector subscript out of range

lhsの要素の数よりnの数が少ない場合いかに対処したらよいのでしょうか
ご教示願えませんでしょうか。

#include <vector>
#include <algorithm>

using namespace std;
template <class T, class OutputIterator>
void matrix_sum(const std::vector<std::vector<T> >& in, OutputIterator out)
{
size_t index = 0;
while (in.begin() + index != in.end()) {
T sum = T();
for (size_t i = 0; i < in.size(); ++i) {
sum += in[i][index];
}
*out = sum;
++out;

++index;
}
}

int main() {

int i, n;

vector<vector<int> >lhs(5);

vector<int>rhs;
for( i = 0; i < 5; ++i) {
//nの値がlhsの要素数未満だとテンプレートが破綻する
for(n = 0; n<4; n++) {
lhs[i].push_back(n);
}
random_shuffle(lhs[i].begin(), lhs[i].end());
}

matrix_sum(lhs, back_inserter(rhs));
copy(rhs.begin(), rhs.end(), ostream_iterator<int>(cout, \n));

return 0;
}


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 22年前
投稿: 1301
 

> lhsの要素の数よりnの数が少ない場合いかに対処したらよいのでしょうか
> ご教示願えませんでしょうか。

どうなって欲しいんですか?
例外throw? 足りない要素は0として扱う? ほかのなにか?


返信引用
とほほ
 とほほ
(@とほほ)
ゲスト
結合: 17年前
投稿: 23
Topic starter  

επιστημηさんお世話になります。

>どうなって欲しいんですか?
lhsのエレメント数 > n 
であってもlhsコンテナ全部に、n個の値代入したいのですが無理なのでしょうか?


返信引用
tetrapod
 tetrapod
(@tetrapod)
ゲスト
結合: 21年前
投稿: 830
 

そもそもの話として「数学的定義上」次元数の違うベクトルは加算できない。
だから valarray は要素数の異なるベクトルを加算できないと最初から決めてる
要素数が異なる場合は未定義動作

動作する必要があるなら「こう動いて欲しい」という仕様を自分で決めて、
それに合致するようにプログラムを実装するのが筋合いだと思うが。

valarray でなく vector にこだわるならこの程度の加算ルーチンを設けて
template<typename iit, typename oit>
oit add_matrix(iit sb, iit se, oit db) {
 while (sb!=se) { *db+=*sb; ++sb; ++db; }
 return db;
}
必要なら assert できるようにこんなふうにしとくか
oit add_matrix(iit sb, iit se, oit db, oit de) {
 assert(distance(sb,se)!=distance(db,de));
 ...
}


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 22年前
投稿: 1301
 

>>どうなって欲しいんですか?
> lhsのエレメント数 > n 
> であってもlhsコンテナ全部に、n個の値代入したいのですが無理なのでしょうか?

だからー、足りない分を何かしらで埋めるだけちゃうのん?
いちいち訊かにゃあかんよなこと?


返信引用
とほほ
 とほほ
(@とほほ)
ゲスト
結合: 17年前
投稿: 23
Topic starter  

お世話になります。
επιστημη さん
了解しました。仕様という事で理解しました
例外は投げれないので0で埋めます。

因みにtetrapod さん
template<typename iit, typename oit>
oit add_matrix(iit sb, iit se, oit db) {
 while (sb!=se) { *db+=*sb; ++sb; ++db; }
 return db;
}
このテンプレートですがiit sb, iit se, oit db
vector<vector<int> >::iterator sb;
vector<int>::iterator se;
vector<vector<int> >::iterator oit;
という事でいいですよね。


返信引用
επιστημη
 επιστημη
(@επιστημη)
ゲスト
結合: 22年前
投稿: 1301
 

> このテンプレートですがiit sb, iit se, oit db
> vector<vector<int> >::iterator sb;
> vector<int>::iterator se;
> vector<vector<int> >::iterator oit;
> という事でいいですよね。

やってみたらわかんじゃないかと。


返信引用
tetrapod
 tetrapod
(@tetrapod)
ゲスト
結合: 21年前
投稿: 830
 

assert の条件が逆だ... orz 直しておいてね
int main() {
int a1[4]={ 1, 2, 3, 4 };
int a2[4]={ 4, 3, 2, 1 };
add_matrix(&a1[1], &a1[4], &a2[0], &a2[3]);
std::copy(&a2[0], &a2[4], std::ostream_iterator<int>(std::cout, ));
return 0;
}
のように使えるわけだな (結果を机上で推論してから実行してみよう)

STL container の全要素を加算、に限定していいなら
template<typename T, typename U>
U& add_containers(const T& src, U& dst) {
typename T::size_type ss(src.size());
typename U::size_type ds(dst.size());
while (ss>ds) { dst.push_back(typename U::value_type()); ++ds; }
typename T::const_iterator sb(src.begin());
typename T::const_iterator se(src.end());
typename U::iterator db(dst.begin());
while (sb!=se) { *db+=*sb; ++sb; ++db; }
return dst;
}

int main() {
std::vector<int> a; a.push_back(1); a.push_back(2);
std::list<int> b; b.push_back(3);// b.push_back(4);
add_containers(a, b);
std::copy(b.begin(), b.end(), std::ostream_iterator<int>(std::cout, ));
std::cout << std::endl;
return 0;
}
こんなのもできるわけで // dst と src は逆のほうが良かったか?

# ...普通ならこんなふうにサンプルコードを提示したりしないのだが
# 数年前の俺を見ているようで他人事とは思えないので...


返信引用
アキラ
 アキラ
(@アキラ)
ゲスト
結合: 23年前
投稿: 49
 

遅くなりました。
簡単に作ったのでエラーチェックもしてなかったですね。

今の要素数の問題を解決したいだけなら
インデックスのチェックを付ければいいだけですけど、遅くはなります

template <class T, class OutputIterator>
void matrix_sum(const std::vector<std::vector<T> >& in, OutputIterator out)
{
size_t index = 0;
while (in.begin() + index != in.end()) {
T sum = T();
for (size_t i = 0; i < in.size(); ++i) {
if (index < in[i].size()) // ※ ここ追加
sum += in[i][index];
}
*out = sum;
++out;

++index;
}
}

これは1つの選択肢なので、tetrapodさんのもあるから
お好みで使い分けてください。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました