計算科学者が独自のバージョンのstd :: complexを実装する必要があるのはなぜですか?


14

ような計算科学における良好知らC ++ライブラリの多くの固有Trilinos、及びdeal.IIは、標準C ++テンプレートヘッダライブラリオブジェクトを使用し、std::complex<>複雑な浮動小数点数を表現します。

ジャックPoulsonのでは答えデフォルトコンストラクタについての質問に、彼は彼が彼の独自の実装を持っていることを指摘std::complexしてエレメンタル「いくつかの理由のために」。それらの理由は何ですか?このアプローチの長所と短所は何ですか?

回答:


16

この議論は、PETScリストで何度も取り上げられていると思います。私の主な理由は次のとおりです。

  1. C ++標準では、std :: complexは、float、double、およびlong doubleデータ型に対してのみ定義されています。したがって、4倍精度などの他のデータ型には使用できません。

  2. この規格は、複雑な算術演算の安定性については保証しません。

  3. 標準では、std :: complex内のデータが実数コンポーネントとそれに続く虚数コンポーネントとして格納されることを保証しません。これは、BLASやLAPACKなどの外部ライブラリとのインターフェースにとって重要です。それはすべての主要な実装に当てはまりますが、私はそれを保証できることを望みます。

  4. 実数成分と虚数成分を直接操作できることを好みます。std :: complexはこれを不必要に難しくします。

  5. 最終的には、フィールドを必要とするのではなく、データ型がリングである必要があるだけのより一般的なバージョンが欲しいです。これには、ガウス整数が含まれます。


6
ポイント3はC ++ 11で対処されました。26.4.4状態その場合z型の左辺値式であるCV std::complex<T>、その後はreinterpret_cast<cv T(&)[2]>(z)reinterpret_cast<cv T(&)[2]>(z)[0]の実部を指定しなければならないz、とreinterpret_cast<cv T(&)[2]>(z)[1]の虚部を指定しなければなりませんz。複素数の配列も扱われます。
ジェームスカスター

3
@JamesCuster:最終的にはC ++ 11に切り替えますが、セミエキゾチックアーキテクチャへの移植性を維持したい科学的なコードは、おそらく少なくとも2〜3年待つ必要があります。また、C ++ 11は残念ながら問題の一部しか解決していません。
ジャックポールソン

将来、誰かがこの質問を見た場合に備えて、私はただそれをそこに放り投げていたのです。
ジェームスカスター

2
さて、コンパイラがC ++ 11をサポートするまで待たなければならないと言うのは警戒だと思います。すべての既存の実装がすでにサポートしているため、明示的な要件が新しい標準に追加されました。他の方法でstd :: complexを実装することはまったく意味をなさないので、既存のコンパイラ/ライブラリでこの特定のレイアウトを既に想定するのが安全でないケースは考えられません。
ウルフギャングバンガース

1
@WolfgangBangerth:C ++ 11への切り替えに関する一般的なコメントでした。いずれにしても、C ++ 11はstd :: complexの問題のほとんどを修正しません。
ジャックポールソン

7

std::complex<>は自分のプログラムで使用していますが、新しいコンパイラーまたはコンパイラーのアップグレードごとに、コンパイラーのフラグと回避策と戦わなければなりません。私はこれらの戦いを時系列に数えてみよう:

  1. std::norm|z|2|z|がオーバーフローを回避する方法で)を、結果を2乗したことがわかりました。この問題は、コンパイルフラグで修正できます-ffast-math
  2. std::arg特定の構成(特定のgccバージョンとのリンク互換性)で非optにコンパイルされたLinux(またはリンカー)上のインテルiccコンパイラー。問題は頻繁に表面化しすぎたためstd::arg、に置き換える必要がありましたatan2(imag(),real())。しかし、新しいコードを書くときにこれを忘れるのはとても簡単でした。
  3. std::complexは、組み込みのC99複合型、および新しいgccバージョンの組み込みのFortran複合型とは異なる呼び出し規則(= ABI)を使用します。
  4. -ffast-math予期しない方法での浮動小数点例外の処理とコンパイルフラグが相互作用。何が起こるかというと、コンパイラーは除算をループから引き出し、それによってdivision by zero実行時に例外を引き起こします。これらの例外は、対応する分割が周囲のロジックのために行われなかったため、ループ内では発生しませんでした。浮動小数点例外処理(異なるコンパイルフラグを使用)を使用するプログラムとは別にコンパイルされ、これらの問題に遭遇する(対応するチームは世界の反対側に座っていたので、この問題は本当にひどいトラブルを引き起こしました)。これは、コンパイラーが使用する最適化を手動でより注意して行うことで解決されました。
  5. ライブラリはプログラムの一部となり、-ffast-mathコンパイルフラグを使用しなくなりました。新しいgccバージョンへのアップグレード後、パフォーマンスが大幅に低下しました。この問題についてはまだ詳しく調査していませんが、C99 Annex Gに関連しているのではないかと心配しています。私は複素数の乗算のこの奇妙な定義に完全に混乱していることを認めざるを得ず、他のバージョンが誤っていると主張するこのバージョンの異なるバージョンが存在するようです。この新しいgccバージョンに-fcx-limited-range関連する別の問題があるように思えるので、コンパイルフラグが問題を解決することを願っています-ffast-math
  6. -ffast-mathコンパイルフラグの挙動になりNaNGCCの新しいバージョン(でものために完全に予測できないisnan影響されます)。唯一の回避策NaNは、プログラム内でのの発生を回避することであるように思われ、これはの存在の目的を無効にしNaNます。

ここでstd::complex、これらの理由により、組み込みの複合型を放棄する予定があるかどうかを尋ねることができます。C ++を使用する限り、組み込み型を使用します。C ++が科学計算で完全に使用できなくなった場合、科学計算に関連する問題をより注意深く処理する言語に切り替えることを検討します。


C99 Annex Gに関連する私の懸念が現実になったように見えます。また、複素数を乗算する際の適切な計算速度には、-fcx-limited-rangeが必要になりました。少なくとも、次の最近の戦争の話から得たものです。medium.com
トーマスクリンペル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.