Previous ToC Next

141. SLLIB (2018/6/4)

C++ で多次元配列を使おうとして困るのは、整合配列がないことです。 これは、関数に多次元配列を渡す時に、その各次元のサイズも渡す、という 機能です。Fortran では太古の昔からあり、 C でも gcc 拡張ではあり、C99 では正式にサポートされました(C11ではサポートはされていますがオプショナ ルですが、サポートしないような腐った処理系を今更使うことはないと思いま す)

で、どういう機能かというと、例えば

   void f(int m, int n, double a[m][n])
   {
      ...
   }
   
というふうに、配列のサイズを渡す機能です。昔の C にはなくて、それでど うやって例えば密行列のライブラリを書くのかよくわからない、というか、 例えば HPL のソースを見るとあらゆるものが1次元配列だったりします。 2次元とか3次元の配列を使いたい偏微分方程式の差分法ソルバでも、 この機能を使わないなら関数には全部1次元配列で渡すとかいうことになります。 もちろん、マクロを使ってサイズがあるのと同じようになんかしてなんかする とかはできます。

で、C は C99 でこれが正式に言語仕様にはいったので、数値計算向けに使う 時のFortran に比べた大きな欠陥の1つは解消したのですが、C++ はこれを 取り入れていません。この結果、C++ で言語標準の機能を 使って多次元の整合配列を関数やライブラリに渡して、ライブラリ側で普通に 多次元配列としてコードを書く方法はありません。

もちろん、C++ なので、なんかクラス作ればいいわけでですが、 そういうのは既に無限に沢山あって、どれを使うべきかわからない、というの が主要な問題です。性能の他、主要な問題は将来的にメンテナンスされそうか どうかです。

JAXA・宇宙科学研究所の SLLIB はそういう無限にあるものの1つですが、宇宙研の公式サポートソフトウェア ということである日突然サポート中止になったりはしなさそうなのが よいところです。

  #include <sli/mdarray.h>
  using namespace sli;
とすると、mdarray_double というクラスができて、例えば

  void printa(mdarray_double a, string s)
  {
      cout << s<<endl;
      unsigned int i,j;
      for (i=0;i < a.length(0); i++){
            for (j=0;j < a.length(1); j++){
              std::cout << "  " << setprecision(8) << a(i,j);
            }
          cout << endl;
      }
  }
こんな感じで配列サイズがメンバ関数にあるので一般のサイズ用の関数がつく れて、デフォルトではアクセスしたところまで適当に要素がとられるので

    mdarray_double u;
    for (int i = 0; i < nx; i++) {
        for (int j = 0; j < ny; j++) {
            u(i,j) = 0.0;
        }
    }
みたいなことができるようです。デフォルトだと範囲チェックが必ずはいるの であんまり速いコードにならない気がしますが、作った時にサイズ固定に するオプションももちろんあります。

もちろんもっとはるかに沢山機能があって 色々便利に使えるようです。expression template はないっぽいので、 どうしてもそういうのが欲しい人は自分でなんとかして下さい。
Previous ToC Next