5

IndexedSeq[Double]ドメイン固有の数値計算ライブラリを設計するときに使用する適切なデータ型 ( など) を探します。この質問では、範囲を の 1 次元配列の操作に限定していますDouble。ライブラリは、1D 配列の各要素に通常適用される数値関数を定義します。

考慮事項:

  • Vectorまたはなどの不変のデータ型を優先するIndexedSeq
  • データ変換を最小限に抑えたい
  • スペースと時間の合理的な効率
  • 図書館を利用する人にやさしい
  • エレガントでクリーンな API

など、コレクション階層の上位にあるものを使用する必要がありますSeqか?

それとも、単一要素の関数を定義して、マッピング/反復をエンド ユーザーに任せた方がよいでしょうか?

これは効率が悪いように見えますが (一部の計算は一連の呼び出しごとに 1 回実行される可能性があるため)、同時に、より柔軟な API です。これは、どのタイプのコレクションでも機能するためです。

推奨事項はありますか?

4

2 に答える 2

11

計算がリモートで計算集約的なことを行う場合はArray、未加工または独自のクラスにラップされた を使用します。コレクション互換のラッパーを提供できますが、相互運用性のためだけに明示的なラッパーにします。以外Arrayはすべて一般的であり、ボックス化されているため、比較的遅くてかさばります。

を使用しないArrayと、人々はあなたが持っているものをすべて放棄しArray、パフォーマンスが重要なときに代わりに使用することを余儀なくされます. 多分それは大丈夫です。おそらく、効率ではなく利便性のために計算をそこに置きたいと思うでしょう。その場合、IndexedSeqインデックス作成が法外に遅くないことを人々に知らせたいと仮定して (たとえば、そうではありませんList)、内部で使用することを想定して、インターフェイスに を使用することをお勧めしますVector。よりも約 4 倍のメモリを使用しArray[Double]、ほとんどの簡単な操作 (乗算など) では 3 倍から 10 倍遅くなります。

たとえば、次のようになります。

val u = v.map(1.0 / _)   //  v is Vector[Double]

これよりも約 3 倍遅いです。

val u = new Array[Double](v.length)
var j = 0
while (j<u.length) {
  u(j) = 1.0/v(j)      // v is Array[Double]
  j += 1
}

mapメソッド onを使用すると、方法Arrayと同じくらい遅くなりVector[Double]ます。上の操作Arrayは一般的であるため、ボックス化されています。(そして、それがペナルティの大部分が発生する場所です。)

于 2012-12-05T16:24:17.460 に答える
3

数値を扱うときは常にベクトルを使用しています。これは、非常に効率的なランダムアクセスと追加/前置を提供するためです。

また、不変のインデックス付きシーケンスの現在のデフォルト コレクションは Vector であるため、 のようなコードを記述した場合for (i <- 0 until n) yield {...}は返されますIndexedSeq[...]が、実行時の型は Vector です。そのため、常にベクトルを使用することをお勧めします。これは、2 つのシーケンスを入力として受け取る一部のバイナリ演算子は、2 つの引数が同じ実装型であるという事実から恩恵を受ける可能性があるためです。(実際にはそうではありませんが、2 番目のパラメーターが単に一般的なシーケンスとして扱われるため、現在の線形時間とは対照的に、ベクトルの連結が log(N) 時間になる可能性があることを指摘した人もいます。)

それでも、Seq[Double]必要な関数インターフェイスのほとんどはすでに提供されているはずです。Vectorまた、Range からのマッピング結果は直接生成されないため、通常Seq[Double]は引数の型を入力として入れて、ある程度の一般性を持たせます。基礎となる実装で効率が最適化されることを期待しています。

それが役立つことを願っています。

于 2012-12-05T15:31:10.590 に答える