Fortran は重い計算では C よりも高速である、または C よりも高速である可能性があることを時々読んでいます。それは本当に本当ですか?私は Fortran についてほとんど知らないことを認めなければなりませんが、これまで見てきた Fortran コードは、この言語が C にはない機能を備えていることを示していませんでした。
本当なら理由を教えてください。数値計算に適した言語やライブラリを教えてください。そのためのアプリやライブラリを作成するつもりはありません。ただ興味があるだけです。
Fortran は重い計算では C よりも高速である、または C よりも高速である可能性があることを時々読んでいます。それは本当に本当ですか?私は Fortran についてほとんど知らないことを認めなければなりませんが、これまで見てきた 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 コンパイラは警告なしで喜んでコンパイルしますが、一部のコンパイラ、一部のハードウェア、および一部の最適化オプションでのみ現れるバグを導入します。
私がプロとしてプログラミングを始めたとき、Fortranの速度の優位性はちょうど挑戦されていました。ドブス博士でそれについて読んで、年配のプログラマーにその記事について話したのを覚えています。彼らは笑いました。
ですから、これについては理論と実践の2つの見方があります。理論的には、今日のFortranには、C / C ++や、アセンブリコードを許可する言語にさえ本質的な利点はありません。実際には、今日のFortranは、数値コードの最適化を中心に構築された歴史と文化の遺産の恩恵を今でも享受しています。
Fortran 77まで、そしてそれを含めて、言語設計の考慮事項は主な焦点として最適化を持っていました。コンパイラの理論と技術の状態により、これは多くの場合、コンパイラにコードの最適化のベストショットを与えるために機能と機能を制限することを意味していました。良い例えは、Fortran77を速度のために機能を犠牲にするプロのレースカーと考えることです。最近、コンパイラーはすべての言語で改善されており、プログラマーの生産性を高める機能がより高く評価されています。しかし、人々が主に科学計算の速度に関心を持っている場所はまだあります。これらの人々は、Fortranプログラマーであった人々からコード、トレーニング、文化を継承している可能性があります。
コードの最適化について話し始めると、多くの問題があります。これを理解するための最良の方法は、高速な数値コードを使用することが仕事である人々がいる場所に潜むことです。ただし、このような非常に機密性の高いコードは、通常、コードの行全体のごく一部であり、非常に特殊化されていることに注意してください。多くのFortranコードは、他の言語の他の多くのコードと同じように「非効率的」であり、最適化はそのようなコードの主な関心事。
Fortranの歴史と文化について学ぶための素晴らしい場所は、ウィキペディアです。Fortran Wikipediaのエントリはすばらしいものであり、Fortranコミュニティにとって価値のあるものにするために時間と労力を費やしてくれた人々に感謝します。
(この回答の短縮版は、ニルスが始めた優れたスレッドのコメントでしたが、それを行うためのカルマはありません。実際、私はおそらく何も書いていなかったでしょうが、そのためにこのスレッドは実際にこのテーマでの私の主な経験である炎の戦争や言語の偏見とは対照的に、情報の内容と共有。私は圧倒され、愛を共有しなければなりませんでした。)
ある程度、Fortranはコンパイラの最適化を念頭に置いて設計されています。この言語は、コンパイラーが並列処理を利用できる配列全体の操作をサポートします(特にマルチコアプロセッサーで)。例えば、
密行列の乗算は単純です。
matmul(a,b)
ベクトルxのL2ノルムは次のとおりです。
sqrt(sum(x**2))
FORALL
さらに、PURE
&ELEMENTAL
proceduresなどのステートメントは、コードの最適化にさらに役立ちます。この単純な理由により、FortranのポインターでさえCと同じくらい柔軟ではありません。
今後のFortran標準(2008)には、並列コードを簡単に記述できるCo-Arrayが含まれています。G95(オープンソース)とCRAYのコンパイラはすでにそれをサポートしています。
つまり、コンパイラーがC / C ++よりもFortranを最適化/並列化できるという理由だけで、Fortranは高速になります。しかし、人生の他のすべてのように、良いコンパイラと悪いコンパイラがあります。
ここで言語を知らないからの答えがたくさんあるのは面白いです。これは、古い FORTRAN 77 コードを開いてその弱点について話し合う C/C++ プログラマーに特に当てはまります。
速度の問題は、ほとんどが C/C++ と Fortran の間の問題だと思います。巨大なコードでは、常にプログラマーに依存します。Fortran が優れている言語の機能もあれば、C が優れている機能もあります。したがって、2011 年には、どちらが速いかは誰にもわかりません。
言語自体については、最近の Fortran は完全な OOP 機能をサポートしており、完全な下位互換性があります。私は Fortran 2003 を徹底的に使用してきました。一部の面では、Fortran 2003 はまだ C++ に遅れをとっていますが、使用法を見てみましょう。Fortran は主に数値計算に使用され、速度上の理由から高度な C++ OOP 機能を使用する人はいません。ハイ パフォーマンス コンピューティングでは、C++ にはほとんど行き場がありません (MPI 標準を見てみると、C++ が非推奨になっていることがわかります!)。
最近では、Fortran と C/C++ を使用した混合言語プログラミングを簡単に行うことができます。Fortran には GTK+ 用のインターフェースもあります。無料のコンパイラ (gfortran、g95) と多くの優れた商用コンパイラがあります。
Fortran の方が高速である理由はいくつかあります。ただし、それらが重要な量は非常に重要ではないか、とにかく回避できるため、問題にはなりません。現在 Fortran を使用する主な理由は、レガシー アプリケーションを維持または拡張することです。
関数の PURE および ELEMENTAL キーワード。これらは、副作用のない関数です。これにより、同じ関数が同じ値で呼び出されることをコンパイラが認識している特定のケースでの最適化が可能になります。注: GCC は、言語の拡張機能として "pure" を実装しています。他のコンパイラも同様です。モジュール間解析でもこの最適化を実行できますが、これは困難です。
個々の要素ではなく、配列を扱う関数の標準セット。sin()、log()、sqrt() などは、スカラーの代わりに配列を取ります。これにより、ルーチンの最適化が容易になります。これらの関数がインラインまたはビルトインである場合、ほとんどの場合、自動ベクトル化は同じ利点をもたらします。
組み込み複合型。理論的には、これによりコンパイラは特定の場合に特定の命令を並べ替えたり削除したりできるようになりますがstruct { double re; double im; };
、C で使用されるイディオムでも同じ利点が得られる可能性があります。ただし、Fortran では演算子が複雑な型で機能するため、開発が高速化されます。
Fortran を支持する重要な点は、Fortran の方がベクトルおよび配列ベースの数学を表現するのにより適しているということです。上で指摘したポインター解析の問題は実際には現実のものです。なぜなら、移植可能なコードは、コンパイラーに何かを伝えることができると実際に想定できないからです。ドメインがどのように見えるかに近い方法で、式の計算には常に利点があります。Cには実際には配列がまったくありません。よく見ると、そのような動作をするものだけです。Fortran には実数の配列があります。これにより、特に並列マシンの特定のタイプのアルゴリズムのコンパイルが容易になります。
実行時システムや呼び出し規約などの奥深くでは、C と最新の Fortran は十分に類似しているため、何が違いを生むのかを理解するのは困難です。ここでの C は実際にはベース C であることに注意してください。C++ はまったく異なる問題であり、パフォーマンス特性が大きく異なります。
ある言語が別の言語よりも速いというようなことはないので、正しい答えはノーです。
あなたが本当に尋ねなければならないのは、「FortranコンパイラXでコンパイルされたコードは、CコンパイラYでコンパイルされた同等のコードよりも速いですか?」です。もちろん、その質問に対する答えは、どちらの2つのコンパイラを選択するかによって異なります。
もう1つの質問は、「コンパイラーの最適化に同じ量の労力を費やした場合、どのコンパイラーがより高速なコードを生成するか」というものです。これに対する答えは、実際にはFortranです。Fortranコンパイラには、証明書の利点があります。
ただし、誰かがCコンパイラの最適化に多大な労力を費やし、プラットフォームのFortranコンパイラよりも優れたコードを生成することを妨げるものは何もありません。実際、Cコンパイラによって生み出される売上が大きいため、このシナリオは非常に実現可能です。
Fortran が C とは異なり、潜在的に高速である別の項目があります。Fortran には、C より優れた最適化ルールがあります。Fortran では、式の評価順序が定義されていないため、コンパイラがそれを最適化できます。特定の順序を強制したい場合は、括弧を使用する必要があります。C では、順序はより厳密ですが、"-fast" オプションを使用すると、より緩和され、"(...)" も無視されます。Fortran にはちょうど中間に位置する方法があると思います。(ええと、IEEE では、特定の評価順序の変更によりオーバーフローが発生しないことが要求されるため、ライブがより困難になります。オーバーフローは無視する必要があるか、評価を妨げます)。
よりスマートなルールのもう 1 つの領域は、複素数です。C 99 まで C がそれらを持っていたというだけでなく、それらを管理する規則も Fortran の方が優れています。gfortran の Fortran ライブラリは部分的に C で書かれていますが、Fortran セマンティクスを実装しているため、GCC はオプションを獲得しました (これは「通常の」C プログラムでも使用できます)。
-fcx-fortran-rules 複雑な乗算と除算は、Fortran の規則に従います。範囲縮小は複素除算の一部として行われますが、複素乗算または除算の結果が "NaN + I*NaN" であるかどうかのチェックは行われず、その場合の状況を救おうとします。
上記のエイリアス規則はもう 1 つの利点であり、少なくとも原則としては、コンパイラのオプティマイザーによって適切に考慮された場合、配列全体の操作により、より高速なコードを導くことができます。反対に、特定の操作に時間がかかることがあります。たとえば、割り当て可能な配列への割り当てを行う場合、多くのチェックが必要です (再割り当て? [Fortran 2003 の機能]、配列のストライドなど)。単純な操作は舞台裏でより複雑になります。したがって遅くなりますが、言語はより強力になります。一方、柔軟な境界とストライドを使用した配列操作により、コードの記述が容易になります。通常、コンパイラは、ユーザーよりも優れたコード最適化を行います。
全体として、C と Fortran はどちらもほぼ同じくらい高速だと思います。どちらの言語がより好きか、または Fortran の配列全体の操作とその優れた移植性を使用することがより有用であるかどうか、または C のシステムおよびグラフィカル ユーザー インターフェイス ライブラリとのより優れたインターフェイスのどちらかを選択する必要があります。
Fortran、C、および C++ の速度を、netlib の古典的な Levine-Callahan-Dongarra ベンチマークと比較します。OpenMP を使用した複数言語バージョンは http://sites.google.com/site/tprincesite/levine-callahan-dongarra-vectors ですコンパイラ。C++ は、該当する場合は STL テンプレートを使用した単なる C です。私の見解では、STL が保守性を向上させるかどうかについては、まちまちです。
例は、インライン化にほとんど依存しない従来の Fortran の慣行に基づいているため、自動関数のインライン化が最適化をどの程度改善するかを確認するために、自動関数のインライン化を最小限実行するだけです。
最も広く使用されている C/C++ コンパイラには、これらのベンチマークが大きく依存している自動ベクトル化がありません。
この直前の投稿を参照してください。Fortran で括弧を使用して、評価のより高速またはより正確な順序を指定する例がいくつかあります。既知の C コンパイラには、より重要な最適化を無効にせずに括弧を監視するオプションがありません。
Fortran と C の速度の違いは、コンパイラの最適化と、特定のコンパイラが使用する基礎となる数学ライブラリの関数になります。C よりも高速になる Fortran 固有の機能はありません。
とにかく、優れたプログラマーは、どの言語でも Fortran を書くことができます。
Fortran 言語と C言語について、特定の目的で一方を他方より高速にするものは何もありません。これらの各言語の特定のコンパイラーについては、特定のタスクを他のものよりも有利にするものがあります。
長年にわたり、数値ルーチンにブラック マジックを実行できる Fortran コンパイラが存在し、多くの重要な計算を非常に高速に実行していました。現代の C コンパイラも同様にできませんでした。その結果、多くの優れたコード ライブラリが Fortran で開発されました。これらの十分にテストされた成熟した素晴らしいライブラリを使用したい場合は、Fortran コンパイラを分解します。
私の非公式な観察によると、最近の人々は重い計算処理を古い言語でコーディングしており、時間がかかる場合は安価な計算クラスターで時間を見つけています。ムーアの法則は私たち全員を馬鹿にします。
私は趣味のプログラマーで、どちらの言語も「平均的」です。C (または C++) コードよりも高速な Fortran コードを書く方が簡単だと思います。Fortran と C はどちらも「歴史的な」言語 (今日の標準) であり、頻繁に使用されており、無料の商用コンパイラが十分にサポートされています。
それが歴史的な事実かどうかはわかりませんが、Fortran は、並列化/分散化/ベクトル化/多コア化されるように構築されているように感じます。そして今日、速度について話しているとき、それはほとんど「標準的な測定基準」です:「それはスケーリングしますか?」
純粋な CPU 処理には、Fortran が大好きです。IOに関連するものについては、Cで作業する方が簡単だと思います(どちらの場合も難しいです)。
もちろん、並列計算を多用するコードでは、おそらく GPU を使用したいと思うでしょう。C と Fortran の両方に、多かれ少なかれ適切に統合された CUDA/OpenCL インターフェイス (および現在は OpenACC) が多数あります。
私の適度に客観的な答えは次のとおりです。両方の言語を同じようによく知っている場合とそうでない場合は、CよりもFortranで並列/分散コードを書く方が簡単だと思うので、Fortranの方が速いと思います.厳密な F77 コードだけではありません)
最初の答えが気に入らないので、私に反対票を投じても構わないと思っている人のための2番目の答えは次のとおりです。両方の言語には、高性能コードを書くために必要な機能があります。つまり、実装しているアルゴリズム (CPU 集中型? IO 集中型? メモリ集中型?)、ハードウェア (シングル CPU? マルチコア? スーパーコンピューターの分散? GPGPU? FPGA?)、スキル、そして最終的にはコンパイラー自体に依存します。C と Fortran には素晴らしいコンパイラがあります。(私は Fortran コンパイラがどれほど高度であるかに真剣に驚いていますが、C コンパイラも同様です)。
PS : Fortran GUI ライブラリについて言いたいことがたくさんあるので、具体的にライブラリを除外してくれてうれしいです。:)
数年間、FORTRAN と C を使用して広範な数学を行っていました。私自身の経験から言えば、FORTRAN は C よりも優れている場合がありますが、その速度のためではなく (適切なコーディング スタイルを使用することで、C を FORTRAN と同じくらい高速に実行できます)、むしろ LAPACK のような非常に最適化されたライブラリのおかげであり、優れた並列化。私の意見では、FORTRAN は非常に扱いにくく、その欠点を補うにはその利点が十分ではありません。そのため、現在は C+GSL を使用して計算を行っています。
Fortan が C より大幅に速いという話は聞いたことがありませんが、場合によっては Fortan の方が速いということも考えられます。そして重要なのは、存在する言語機能ではなく、(通常) 存在しない言語機能にあります。
例は C ポインタです。C ポインターはどこでも使用されていますが、ポインターの問題は、通常、コンパイラーが同じ配列の異なる部分を指しているかどうかを判断できないことです。
たとえば、次のような strcpy ルーチンを作成したとします。
strcpy(char *d, const char* s)
{
while(*d++ = *s++);
}
コンパイラは、d と s が重複する配列である可能性があるという仮定の下で動作する必要があります。そのため、配列がオーバーラップしたときに異なる結果を生成する最適化を実行することはできません。ご想像のとおり、これにより、実行できる最適化の種類が大幅に制限されます。
[C99 には、ポインターがオーバーラップしないことを明示的にコンパイラーに伝える「restrict」キーワードがあることに注意してください。また、Fortran にもポインターがあり、セマンティクスは C のものとは異なりますが、ポインターは C のようにどこにでもあるわけではありません。]
しかし、C と Fortran の問題に戻ると、Fortran コンパイラーは (単純に書かれた) C プログラムでは実行できない最適化を実行できると考えられます。ですから、私はこの主張にあまり驚かないでしょう。ただし、パフォーマンスの違いはそれほど大きくないと思います。[~5-10%]
一般に、FORTRAN は C よりも低速です。C はハードウェア レベルのポインターを使用して、プログラマーが手動で最適化できるようにします。FORTRAN (ほとんどの場合) は、ハードウェア メモリ アドレッシング ハックにアクセスできません。(VAX FORTRAN はまた別の話です。) 私は 70 年代から FORTRAN をオンとオフで使用してきました。(本当。)
ただし、90 年代以降、FORTRAN は進化して、マルチコア プロセッサで実際に叫ぶことができる本質的に並列なアルゴリズムに最適化できる特定の言語構造を含むようになりました。たとえば、自動ベクトル化では、複数のプロセッサがデータのベクトル内の各要素を同時に処理できます。16 プロセッサ -- 16 要素ベクトル -- 処理にかかる時間は 1/16 です。
C では、独自のスレッドを管理し、マルチプロセッシング用にアルゴリズムを慎重に設計し、一連の API 呼び出しを使用して、並列処理が適切に行われるようにする必要があります。
FORTRAN では、マルチプロセッシングのためにアルゴリズムを慎重に設計するだけで済みます。コンパイラとランタイムが残りを処理します。
High Performance Fortranについて少し読むことができますが、多くのデッドリンクが見つかります。並列プログラミング ( OpenMP.org など) と、FORTRAN がそれをどのようにサポートしているかについて読んだほうがよいでしょう。
より高速なコードは実際には言語に依存していません。コンパイラであるため、「.exe」内で結合された肥大化した、遅くて冗長なオブジェクトコードを生成するms-vb「コンパイラ」を見ることができますが、powerBasicは生成しすぎますより良いコード。C および C++ コンパイラで作成されたオブジェクト コードはいくつかのフェーズ (少なくとも 2 つ) で生成されますが、設計上、ほとんどの Fortran コンパイラには高レベルの最適化を含む少なくとも 5 つのフェーズがあるため、Fortran は常に高度に最適化されたコードを生成する機能を備えています。最後にコンパイラーはあなたが求めるべき言語ではありません.私が知っている最高のコンパイラーはインテル Fortran コンパイラーです. OpenWatcom でいつでもリレーできる安価なコンパイラ。
これに関する詳細情報: http://ed-thelen.org/1401Project/1401-IBM-Systems-Journal-FORTRAN.html
最新の標準とコンパイラを使用して、いいえ!
ここにいる何人かは、コンパイラがエイリアシングを心配する必要がないため (したがって、最適化中により多くの仮定を行うことができる)、FORTRAN の方が高速であると示唆しています。ただし、これは C99 (私が思うに) 標準以降、restrict キーワードを含めて C で処理されています。これは基本的に、特定のスコープ内でポインターがエイリアス化されていないことをコンパイラーに伝えます。さらに、C では適切なポインター演算が可能であり、エイリアシングなどはパフォーマンスとリソース割り当ての点で非常に役立ちます。FORTRANの最新バージョンでは、「適切な」ポインターを使用できると思いますが。
最近の実装では、C 全般が FORTRAN よりも優れています (ただし、非常に高速でもあります)。
http://benchmarksgame.alioth.debian.org/u64q/fortran.html
編集:
これに対する公正な批判は、ベンチマークが偏っている可能性があるということです。結果をより多くのコンテキストに置く別のソース(Cに関連する)を次に示します。
http://julialang.org/benchmarks/
C は通常、ほとんどの場合に Fortran よりも優れていることがわかります (ここでも適用される以下の批判を参照してください)。他の人が述べているように、ベンチマークは、ある言語を他の言語よりも優先するために簡単にロードできる不正確な科学です。しかし、Fortran と C のパフォーマンスがどのように似ているかを説明しています。
Fortran には優れた I/O ルーチンがあります。たとえば、暗黙の do 機能により、C の標準ライブラリに匹敵しない柔軟性が得られます。
Fortran コンパイラは、関連するより複雑な構文を直接処理します。そのような構文は、引数を渡す形式に簡単に縮小できないため、C では効率的に実装できません。
これは、何よりもコンパイラの品質などに関係するため、やや主観的なものではありません。ただし、質問にもっと直接的に答えるために、言語/コンパイラの観点から言えば、C よりも本質的に高速または優れた Fortran については何もありません。重い数学演算を実行している場合、それはコンパイラの品質、各言語のプログラマのスキル、およびこれらの操作をサポートする組み込みの数学サポート ライブラリを使用して、特定の実装でどちらが高速になるかを最終的に決定します。
編集: @Nils などの他の人々は、C でのポインターの使用の違いと、C でおそらく最も素朴な実装を遅くするエイリアシングの可能性について良い点を提起しました。ただし、C99 でそれを処理する方法があります。 、コンパイラの最適化フラグを介して、および/またはCが実際にどのように記述されているかで。これは、@Nilsの回答と、彼の回答に続くコメントで十分にカバーされています。
ほとんどの投稿はすでに説得力のある議論を示しているので、私は別の側面にことわざの2セントを追加します。
最終的に処理能力の点でFortranを速くしたり遅くしたりすることは重要ですが、Fortranで何かを開発するのに5倍の時間がかかる場合は、次の理由があります。
その場合、問題は無関係です。何かが遅い場合、ほとんどの場合、与えられた制限を超えてそれを改善することはできません。より高速なものが必要な場合は、アルゴリズムを変更してください。結局、コンピューターの時間は安いです。人間の時間はそうではありません。人間の時間を短縮する選択を大切にしてください。それがコンピュータ時間を増やすならば、それはとにかく費用効果が高いです。
Fortran は伝統的に -fp:strict などのオプションを設定しません (ifort は、f2003 標準の一部である USE IEEE_arithmetic の一部の機能を有効にする必要があります)。Intel C++ もデフォルトとして -fp:strict を設定しませんが、これはたとえば ERRNO 処理に必要です。また、他の C++ コンパイラでは、ERRNO をオフにしたり、simd リダクションなどの最適化を行ったりするのは便利ではありません。gcc と g++ では、危険な組み合わせ -O3 -ffast-math -fopenmp -march=native の使用を避けるために Makefile をセットアップする必要がありました。これらの問題以外に、相対的なパフォーマンスに関するこの質問は、より細かくなり、コンパイラとオプションの選択に関するローカル ルールに依存します。