Fortran は C よりも重い計算を最適化するのが簡単ですか?

言語には同様の機能セットがあります。パフォーマンスの違いは、EQUIVALENCE ステートメントが使用されない限り、Fortran がエイリアシングを許可しないと言うことから生じます。エイリアシングのあるコードはすべて有効な 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 この問題に対処するために、キーワードと厳密なエイリアスが C99 標準に導入されました。最近では、ほとんどの C++ コンパイラでも十分にサポートされています。このキーワードを使用すると、ポインターが他のポインターとエイリアスしないことをプログラマーが約束しているというヒントをコンパイラーに与えることができます。厳密なエイリアシングとは、たとえば double* のように、異なる型のポインターが重複しないことをプログラマーが約束することを意味します。 int* と重複しません (ただし、char* という特定の例外があります および void* 何とでも重ねることができます)。

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


はい、1980 年です。 2008年に?依存

私が専門的にプログラミングを始めたとき、Fortran の速度優位性はまさに挑戦されていました。 Dr. Dobbs でそれについて読んで、年配のプログラマーにその記事について話したのを覚えています - 彼らは笑っていました.

したがって、私はこれについて、理論的および実際的な 2 つの見解を持っています。 理論上 今日の Fortran には、C/C++ や、アセンブリ コードを使用できる言語に対してさえ、本質的な利点はありません。 実際に 今日の Fortran は、数値コードの最適化を中心に構築された歴史と文化の遺産の恩恵を受けています。

Fortran 77 までは、言語設計の考慮事項の主な焦点は最適化でした。コンパイラの理論と技術の状態により、これは多くの場合制限を意味します。 コンパイラにコードを最適化するための最良の方法を提供するための機能と機能。 Fortran 77 を、速度のために機能を犠牲にしたプロのレーシングカーと考えると、わかりやすい例えになります。最近では、コンパイラーはすべての言語で改善されており、プログラマーの生産性のための機能がより重視されています。ただし、人々が主に科学計算の速度に関心を持っている場所がまだあります。これらの人々は、Fortran プログラマーだった人々からコード、トレーニング、文化を受け継いでいる可能性が高いです。

コードの最適化について話し始めると、多くの問題が発生します。これを理解するための最良の方法は、高速な数値コードを作成する仕事をしている人々がどこにいるかを知ることです。ただし、このような非常に機密性の高いコードは、通常、コード行全体のごく一部であり、非常に特殊化されていることに注意してください。Fortran コードの多くは、他の言語の他の多くのコードと同じように「非効率的」であり、最適化を行うべきではありません。そのようなコードの主な関心事.

Fortran の歴史と文化について学ぶのに最適な場所は、ウィキペディアです。 Fortran ウィキペディアのエントリはすばらしいものであり、Fortran コミュニティにとって価値あるものにするために時間と労力を費やしてくれた人々に感謝します。

(この回答の短縮版は、Nils によって開始された優れたスレッドのコメントでした。 しかし、私にはそれを行うカルマがありません。実際、私はおそらく何も書いていなかったでしょうが、このスレッドには、この主題に関する私の主な経験であるフレーム戦争や言語の偏見とは対照的に、実際の情報コンテンツと共有があります.私は圧倒され、愛を分かち合わなければなりませんでした。)


Fortran は、コンパイラの最適化を念頭に置いて設計されています。この言語は、コンパイラが並列処理を利用できる配列全体の操作をサポートしています (特にマルチコア プロセッサ上で)。たとえば、

密行列の乗算は単純です:

matmul(a,b)

ベクトル x の L2 ノルムは:

sqrt(sum(x**2))

さらに FORALL などのステートメント 、 PURE &ELEMENTAL 手順などは、コードの最適化にさらに役立ちます。この単純な理由により、Fortran のポインターでさえ C ほど柔軟ではありません。

今後の Fortran 標準 (2008 年) には、並列コードを簡単に記述できる co-array があります。 G95 (オープン ソース) と CRAY のコンパイラは既にサポートしています。

そうです、コンパイラがC/C++よりも最適化/並列化できるという理由だけで、Fortranは高速になる可能性があります。しかし、繰り返しになりますが、人生の他のすべてのものと同様に、良いコンパイラと悪いコンパイラがあります.