いつもお世話になります。
複数のコンテナがあり各ベクトルの要素数は同じこととします。
各コンナの同じ要素番号の値を全て加算して他のコンテナに代入する。
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
あったとしてもふたつまで。
επιστημη さんいつもお世話になります。
インデントがガタガタですみません。
>あったとしてもふたつまで。
そうですか250×500以上のmatrixになるので無理ですね
lhs[n]型のvectorコンテナを宣言するのも250個イテレータを宣言するのも250個なので
テストコードをタイピングするのもあほらしいので秀丸マクロで書いたのですが
こんなのでいいのってな感じです。
「stl vector 行列演算」で検索するとεπιστημη さんのところの
過去ログがヒットし只今調査中しています雰囲気ではvalarray の
gsliceクラスが使えそうな感じなのですが私には敷居が高い感じです。
Lokiとかは無理ですがBoostなら使ったことがあるのでそれも視野に入れて探してみま
す。
簡単ですけど、こうかな
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;
}
もしくはこうかな
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;
}
ソースコードの見た目も大事だが実行速度も大事なのであって
データキャッシュヒット率を考えてコード書く必要があるかもしんないよ
配列の各要素がメモリ上で連続するので、でかい配列が複数ある場合、
・同一配列に対する操作はキャッシュヒット率が高く
・異なる配列の同一インデックスに対する操作はキャッシュヒット率が低い
ことが容易に予想される
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;
計測してないので真偽のほどはなんともいえないけどさ
アキラ さん、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;
}
> lhsの要素の数よりnの数が少ない場合いかに対処したらよいのでしょうか
> ご教示願えませんでしょうか。
どうなって欲しいんですか?
例外throw? 足りない要素は0として扱う? ほかのなにか?
επιστημηさんお世話になります。
>どうなって欲しいんですか?
lhsのエレメント数 > n
であってもlhsコンテナ全部に、n個の値代入したいのですが無理なのでしょうか?
そもそもの話として「数学的定義上」次元数の違うベクトルは加算できない。
だから 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));
...
}
>>どうなって欲しいんですか?
> lhsのエレメント数 > n
> であってもlhsコンテナ全部に、n個の値代入したいのですが無理なのでしょうか?
だからー、足りない分を何かしらで埋めるだけちゃうのん?
いちいち訊かにゃあかんよなこと?
お世話になります。
επιστημη さん
了解しました。仕様という事で理解しました
例外は投げれないので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;
という事でいいですよね。
> このテンプレートですがiit sb, iit se, oit db
> vector<vector<int> >::iterator sb;
> vector<int>::iterator se;
> vector<vector<int> >::iterator oit;
> という事でいいですよね。
やってみたらわかんじゃないかと。
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 は逆のほうが良かったか?
# ...普通ならこんなふうにサンプルコードを提示したりしないのだが
# 数年前の俺を見ているようで他人事とは思えないので...
遅くなりました。
簡単に作ったのでエラーチェックもしてなかったですね。
今の要素数の問題を解決したいだけなら
インデックスのチェックを付ければいいだけですけど、遅くはなります
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さんのもあるから
お好みで使い分けてください。