重い計算の場合、Fortran は C よりも最適化しやすいですか? 質問する

重い計算の場合、Fortran は C よりも最適化しやすいですか? 質問する

時々、Fortran は重い計算では C より速い、または速くなる可能性があるという記事を読みます。それは本当でしょうか? 私は Fortran についてほとんど知らないと言わざるを得ませんが、これまで見た Fortran コードでは、この言語には C にはない機能があることは示されていませんでした。

もしそれが本当なら、その理由を教えてください。数値計算に適した言語やライブラリは何か教えないでください。そのためのアプリやライブラリを書くつもりはなく、ただ知りたいだけです。

ベストアンサー1

これらの言語には類似した機能セットがあります。パフォーマンスの違いは、Fortran では EQUIVALENCE ステートメントを使用しない限りエイリアシングが許可されないという事実から生じます。エイリアシングのあるコードは有効な Fortran ではありませんが、これらのエラーを検出するのはコンパイラではなくプログラマーの責任です。したがって、Fortran コンパイラはメモリ ポインターのエイリアシングの可能性を無視し、より効率的なコードを生成できるようにします。C の次の小さな例を見てみましょう。

void transform (float *output, float const * input, float const * matrix, int *n)
{
    int i;
    for (i=0; i<*n; i++)
    {
        float x = input[i*2+0];
        float y = input[i*2+1];
        output[i*2+0] = matrix[0] * x + matrix[1] * y;
        output[i*2+1] = matrix[2] * x + matrix[3] * y;
    }
}

この関数は、最適化後、Fortran の対応する関数よりも実行速度が遅くなります。なぜでしょうか? 出力配列に値を書き込むと、マトリックスの値が変わる可能性があります。結局、ポインターが重複して、同じメモリ チャンク (ポインターを含むint!) を指す可能性があります。C コンパイラーは、すべての計算で 4 つのマトリックス値をメモリから再ロードする必要があります。

Fortran では、コンパイラは行列の値を一度ロードしてレジスタに格納できます。これは、Fortran コンパイラがポインタ/配列がメモリ内で重複しないと想定しているため可能です。

幸いなことに、restrictこの問題に対処するために、キーワードと strict-aliasing が C99 標準に導入されました。これは、最近のほとんどの C++ コンパイラでも十分にサポートされています。キーワードを使用すると、プログラマーがポインターが他のポインターとエイリアスしないことを約束していることをコンパイラーに知らせることができます。strict-aliasing は、プログラマーが異なる型のポインターが決して重複しないことを約束することを意味します。たとえば、 a はdouble*an と重複しません(ただし、 と は他のものと重複できるint*という特定の例外があります)。char*void*

これらを使用すると、C と Fortran で同じ速度が得られます。ただし、restrictパフォーマンスが重要な関数でのみキーワードを使用できるということは、C (および C++) プログラムがより安全で簡単に記述できることを意味します。たとえば、無効な Fortran コードを考えてみましょう。CALL TRANSFORM(A(1, 30), A(2, 31), A(3, 32), 30)ほとんどの Fortran コンパイラは警告なしで問題なくコンパイルしますが、一部のコンパイラ、一部のハードウェア、および一部の最適化オプションでのみ発生するバグが発生します。

おすすめ記事