- ベストアンサー
ループカウンタを使用せず、配列の全てを足したい
質問です。 配列を使い、その値の合計値を出す際に私はループカウンタを利用して足す手法を 思いつくのですが、それ以外の方法があると聞きました。 ですが、それ以外の方法が思いつかなく質問させてください。 int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int nSum = 0; for ( int i = 0; i < 10; i++ ) { nSum += a[i]; } return nSum; ここでループカウンタを使用せず、配列の全てを足すにはどうしたら良いでしょうか。
- みんなの回答 (11)
- 専門家の回答
質問者が選んだベストアンサー
C++なら、No1の回答者さんがおっしゃるようにSTLのaccumulateを 使うのが簡単だと思います。 自分で実装するのであればポインタを使って for (int *p=a; p<a+10; p++) { nSum += *p; } のように書くこともできます。 カウンタのほうが分かりやすくてよいと思いますが。
その他の回答 (10)
- don_go
- ベストアンサー率31% (336/1059)
配列の最後に終端となるデータを設定して int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1 }; int nSum = 0; int *p = a; for(; *p >= 0; *p++) { nSum += *p; } または while (*p>=0) { nSum += *p++; };
- noocyte
- ベストアンサー率58% (171/291)
#8 さん > 一番高速という意味では、 > (中略) > だと思います。 確かに.(^^; ループアンローリングという手がありましたね. #9 さん > x86系CPUなら > [(ベースアドレス)+(1要素サイズ)*(オフセット)] > のアドレスに格納されているの値の参照を1クロックで > 行うことができるので、 そうなんですが,要素サイズは 1,2,4,8 バイト限定ですよね. 今回のように要素が基本データ型ならいいんですが,一般の構造体だと使えない場合が多いですね.
- tea_sheep
- ベストアンサー率53% (8/15)
少なくともx86系CPUなら [(ベースアドレス)+(1要素サイズ)*(オフセット)] のアドレスに格納されているの値の参照を1クロックで 行うことができるので、ループカウンタを使用することで 遅くなるということはないと思います。 まあ、ループ内で行う処理や最適化の質にもよるでしょうけど。 ループ数が固定なら、コンパイラによってはNo.8のような 形にまで最適化してくれるそうですし。
- jacta
- ベストアンサー率26% (845/3158)
一番高速という意味では、 int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; return a[0]+a[1]+a[2]+a[3]+a[4]+a[5]+a[6]+a[7]+a[8]+a[9]; だと思います。 一般に、効率を上げるには汎用性を捨てるのが最も効果的です。
- Oh-Orange
- ベストアンサー率63% (854/1345)
★あぁ…間違った! ・noocyte さん、ご指摘有り難う御座います。 ●質問者さんへ ・間違い⇒『nSum += *a++;』 ・正しい⇒『nSum += *p++;』 ・以上。すみませんでした。
- noocyte
- ベストアンサー率58% (171/291)
#3 です. #5 さんに先に書かれちゃいましたが,これがたぶん一番高速な (少なくとも他の方法より遅くはないはず) 方法です. (なので私はよく使います.) int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int nSum = 0; // 以下,#5 さんと実質的に同じコード const int * const endOfArray = &a[10]; // a[] の直後のアドレスを指す. const int *element = a; // a[] の要素を指す. while(element < endOfArray) nSum += *element++; この方法だと,ループ内の処理は, (どうせやらないといけない,配列要素の参照と nSum への加算を除けば) 次の2つだけです. ・element < endOfArray の判定 ・element++ 他方質問文のように,普通にループカウンタを添字にする方法だと, 次の処理が必要です. ・i < 10 の判定 ・i++ ・i から &a[i] を求める処理.つまり次の2つ. size_t offset = sizeof(a[i]) * i; // a[] の先頭に対する a[i] のバイト・オフセット const char *address = (char*)a + offset; // a[i] のバイトアドレス (もっとも,後者はコンパイラが最適化によって 前者のようなコードに変換してくれるかもしれません.) #4 さん > nSum += *a++; a は定数なのでエラーですよ~.(笑)
- Oh-Orange
- ベストアンサー率63% (854/1345)
★『配列の添え字を使うな!』という事かな? ・それならば、配列をポインタにセットして要素分だけループして加算します。 ・これ以外では、私も思い浮かびません。 ・下にサンプルを載せます。 サンプル: int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int *p = a; int nSum = 0; for ( int i = 0 ; i < 10 ; i++ ){ nSum += *a++; } return nSum; 最後に: ・配列とポインタの学習ですかね。 ・やっぱり『ループカウンタを使用せず』の意味がよく分かりません。 ・とりあえず、上記のサンプルをどうぞ。 ・以上。おわり。
お礼
配列とポインタの学習、その通りです。 使うだけなら、こう使えば動く。としか知らない面が多く それを実際に職業にしている方から、違う方法もあるよ。と言われたもので・・・ 参考にさせていただきます!
- noocyte
- ベストアンサー率58% (171/291)
再帰呼び出しを使う方法もあります. int a[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int SumOfArray(const int array[], unsigned nElements) { return (nElements <= 0) ? 0 : (array[0] + SumOfArray(array + 1, nElements - 1)); } int main(void) { int nSum = SumOfArray(a, 10); printf("nSum = %d\n", nSum); return 0; } ループカウンタを使う場合に比べて遅いし, 配列の要素数が非常に多いとスタックオーバーフローしてしまいますが. /* 私はCよりも先に Lisp を覚えました.(笑) */
お礼
おー!こんな方法もあるんですね! >ループカウンタを使う場合に比べて遅いし, >配列の要素数が非常に多いとスタックオーバーフローしてしまいますが. 私はまだまだ初心者なので、方法として教えて頂けたのは大変ありがたいです!
>ループカウンタを使用せず というのが配列の要素を指定するのに使わない という意味なら下記のようにすることができます 配列の最後の要素にストッパーとしての値を入れて それを検出するまで加算、という風にすればfor文を使わなくても実現できます -----引用 /* 正数のカウント */ for( i = 0; i < inputCount; i++ ){ if ( *data > 0 ){ sum = sum + *data; count++; } data++; } http://www.na.rim.or.jp/~m_tanabe/c/pointer8.html -----引用
お礼
>ループカウンタを使用せず というのが配列の要素を指定するのに使わない という意味なら下記のようにすることができます その通りです。言葉が足りずすみません。 引用サイト見てみます!ありがとうございます
- koko_u_
- ベストアンサー率18% (459/2509)
STL オーケーなら template<typename InputIterator, typename Type> Type accumulate( InputIterator first, InputIterator last, Type init );
お礼
なるほど! STL調べてみます!
お礼
なるほど、ポインタをそのまま当てはめ pをインクリメントしていくわけですね! 参考にさせていただきます!