時々、Fortranが重い計算のために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コンパイラーは、ポインター/配列がメモリー内でオーバーラップしないと想定しているため、そうすることができます。
幸いなことに、この問題に対処するために、C99標準に restrict
キーワードとストリクトエイリアスが導入されました。最近のほとんどの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までは、言語設計の考慮事項に最適化が主な焦点でした。コンパイラの理論と技術の状態により、これは多くの場合、制限機能と能力を意味し、コンパイラにコードの最適化のベストショットを提供します。 Fortran 77を、スピードのために機能を犠牲にしたプロのレースカーと考えるのは良い例えです。最近では、コンパイラーはすべての言語で改善されており、プログラマーの生産性のための機能がより重視されています。ただし、人々が主に科学計算の速度に関心を持っている場所はまだあります。これらの人々は、Fortranプログラマーである人々からコード、トレーニング、文化を継承している可能性が高いです。
コードの最適化について話し始めると、多くの問題があり、これを感じるための最良の方法は 高速な数値コードを取得することを仕事にしている人々に潜む です。ただし、このような非常に機密性の高いコードは通常、コード行全体のごく一部であり、非常に特殊化されていることに注意してください。Fortranコードの多くは、他の言語の他のコードと同様に「非効率」であり、 最適化そのようなコードの主要な関心事でさえないはずです 。
Fortranの歴史と文化について学ぶことから始める素晴らしい場所はウィキペディアです。 Fortran Wikipediaのエントリ はすばらしいものであり、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は高速になります。しかし、人生の他のすべてのものと同様に、良いコンパイラと悪いコンパイラがあります。
ここで多くの答えが言語を知らないことから面白いことです。これは特に、古いFORTRAN 77コードを開いて弱点について議論したC/C++プログラマーに当てはまります。
速度の問題は主にC/C++とFortranの間の問題だと思います。巨大なコードでは、常にプログラマーに依存します。 Fortranに勝る言語の機能とCが行う機能があります。したがって、2011年には、どっちが速いかを誰も実際に言うことができません。
言語自体については、Fortranは現在、完全なOOP機能をサポートしており、完全な下位互換性があります。 Fortran 2003を徹底的に使用しましたが、Fortran 2003を使用するのは楽しいことだと思います。一部の側面では、Fortran 2003はまだC++の背後にありますが、使用方法を見てみましょう。 Fortranは主に数値計算に使用され、速度上の理由から、派手なC++ OOP機能を使用する人はいません。ハイパフォーマンスコンピューティングでは、C++には行く場所がほとんどありません(MPI標準を見て、C++が非推奨になっていることがわかります!)。
最近では、FortranとC/C++を使用して混合言語プログラミングを簡単に行うことができます。 FortranにはGTK +用のインターフェースもあります。無料のコンパイラ(gfortran、g95)と多くの優れた市販のコンパイラがあります。
Fortranが高速になる理由はいくつかあります。ただし、重要な金額はあまり重要ではないか、とにかく回避できるため、問題ではありません。今日Fortranを使用する主な理由は、レガシーアプリケーションの保守または拡張です。
関数のPUREおよびELEMENTALキーワード。これらは副作用のない関数です。これにより、コンパイラが同じ値で同じ関数が呼び出されることがわかっている特定の場合に最適化が可能になります。 注:GCCは、言語の拡張として「純粋」を実装します。他のコンパイラも同様です。モジュール間分析もこの最適化を実行できますが、困難です。
個々の要素ではなく、配列を処理する関数の標準セット。 sin()、log()、sqrt()のようなものは、スカラーの代わりに配列を取ります。これにより、ルーチンの最適化が容易になります。 自動ベクトル化は、これらの関数がインラインまたは組み込み関数である場合、ほとんどの場合同じ利点を提供します
組み込みの複合型。理論的には、これによりコンパイラは特定の場合に特定の命令を並べ替えたり削除したりできますが、struct {double re、im; }; Cで使用されるイディオム。演算子はfortranで複雑な型を扱うため、開発が高速になります。
Fortranを支持する重要なポイントは、Fortranがベクトルおよび配列ベースの数学を表現するのに少し適した言語であると思うことです。上記で指摘されたポインター解析の問題は実際には現実的です。なぜなら、移植可能なコードは、コンパイラーに何かを伝えることができると実際に想定できないからです。ドメインがどのように見えるかに近い方法で計算を表現することには、常に利点があります。よく見ると、Cには実際には配列がありません。 Fortranには本当の意味があります。これにより、特定の種類のアルゴリズム、特に並列マシン向けのコンパイルが容易になります。
ランタイムシステムや呼び出し規約などの深いところにあるCと現代のFortranは、何が違いをもたらすのかを理解するのが難しいほど十分に類似しています。ここでのCは実際にはベースCであることに注意してください。C++はパフォーマンス特性がまったく異なる、まったく異なる問題です。
ある言語が別の言語より速いということはないので、適切な答えはnoです。
本当に尋ねなければならないのは、「FortranコンパイラXでコンパイルされたコードは、CコンパイラYでコンパイルされた同等のコードよりも高速ですか?」です。もちろん、その質問に対する答えは、どちらのコンパイラを選択するかによって異なります。
もう1つ質問できるのは、「コンパイラで最適化に注がれた労力と同じ量を与えれば、どのコンパイラがより高速なコードを生成するのか」ということです。これに対する答えは、実際にはFortranです。 Fortranコンパイラには、次の利点があります。
ただし、Cコンパイラの最適化に多大な労力を費やし、プラットフォームのFortranコンパイラよりも優れたコードを生成できるようにすることを妨げるものは何もありません。実際、Cコンパイラによって生成された売り上げが大きいため、このシナリオは非常に実現可能です。
FortranがCとは異なる別の項目があり、潜在的に高速です。 FortranにはCよりも優れた最適化ルールがあります。Fortranでは、式の評価順序が定義されていないため、コンパイラーは式を最適化できます。特定の順序を強制する場合は、括弧を使用する必要があります。 Cでは順序ははるかに厳密ですが、「-fast」オプションを使用すると、より緩和され、「(...)」も無視されます。 Fortranには、中間にある方法があると思います。 (まあ、IEEEは特定の評価順序の変更がオーバーフローを発生させないことを要求するため、ライブをより難しくします。オーバーフローは無視するか、評価を妨害します)。
よりスマートなルールのもう1つの領域は、複素数です。 CがCを持っているのはC 99までかかっただけでなく、それらを管理する規則もFortranの方が優れています。 gfortranのFortranライブラリは部分的にCで書かれていますが、Fortranセマンティクスを実装しているため、GCCはオプションを取得しました(「通常の」Cプログラムでも使用できます)。
-fcx-fortran-rules複雑な乗算と除算は、Fortranの規則に従います。範囲の縮小は、複雑な除算の一部として行われますが、複素数の乗算または除算の結果が「NaN + I * NaN」であるかどうかのチェックは行われず、その場合の状況を救おうとします。
上記の別名規則は別のボーナスであり、少なくとも原則として、コンパイラーのオプティマイザーによって適切に考慮される場合、コード全体を高速化できる配列全体の操作も可能です。反対に、特定の操作にはさらに時間がかかります。割り当て可能な配列に割り当てを行う場合、多くのチェックが必要です(再割り当てしますか?[Fortran 2003の機能]、配列のストライドなど)。言語をより強力にします。一方、柔軟な境界とストライドを備えた配列演算は、コードの記述を容易にします。通常、コンパイラはユーザーよりもコードを最適化する方が優れています。
全体として、CとFortranはどちらもほぼ同じくらい高速だと思います。選択する言語は、より多くの言語を選択するか、Fortranの配列全体の操作を使用して移植性を向上させるか、またはCのシステムおよびグラフィカルユーザーインターフェイスライブラリとのインターフェイスを改善するかです。
言語 FortranとCには、特定の目的で一方を他方より速くするものは何もありません。特定のタスクに対して他の言語よりも有利な言語を作成するこれらの言語のそれぞれについて、特定のコンパイラに関するものがあります。
長年、Fortranコンパイラが存在し、数値ルーチンに黒魔術をかけ、多くの重要な計算を非常に高速に実行できました。現代のCコンパイラはそれもできませんでした。その結果、Fortranでは多くの優れたコードライブラリが成長しました。これらの十分にテストされた成熟したすばらしいライブラリを使用したい場合は、Fortranコンパイラを使用します。
私の非公式の観察によると、最近の人々は重い計算を古い言語でコーディングしており、時間がかかる場合は安価な計算クラスターで時間を見つけます。ムーアの法則は私たちすべてを馬鹿にします。
私は数年間、FORTRANとCで大規模な数学をやっていた。私自身の経験から、FORTRANはCよりも優れていることもありますが、その速度(適切なコーディングスタイルを使用してCをFORTRANと同じくらい高速に実行できる)ではなく、LAPACKなどの非常によく最適化されたライブラリのために、優れた並列化。私の意見では、FORTRANは本当に扱いにくく、その利点はその欠点を解消するのに十分ではないので、計算を行うためにC + GSLを使用しています。
私は趣味のプログラマーで、両方の言語で「平均的」です。 C(またはC++)コードよりも高速なFortranコードを書く方が簡単だと思います。 FortranとCはどちらも(今日の標準では)「歴史的な」言語であり、頻繁に使用されており、無料および商用のコンパイラを十分にサポートしています。
それが歴史的な事実かどうかはわかりませんが、Fortranは、並列化/分散化/ベクトル化/あらゆる多コア化のために構築されているように感じます。そして今日、速度について話しているとき、それはほとんど「標準的なメトリック」です:「それはスケーリングしますか?」
純粋なCPUクランチには、Fortranが大好きです。 IOに関連するものなら何でも、Cで作業する方が簡単だと思います(どちらの場合も難しいです)。
もちろん、並列数学を集中的に使用するコードの場合は、おそらくGPUを使用する必要があります。 CとFortranの両方には、多かれ少なかれよく統合されたCUDA/OpenCLインターフェース(そして今やOpenACC)がたくさんあります。
私の適度に客観的な答えは次のとおりです。両方の言語を等しく/貧弱に知っているなら、FortranはCよりも並列/分散コードを書く方が簡単だと思うので、Fortranの方が速いと思います。厳密なF77コードだけではありません)
1つ目の答えが気に入らないので、私に賛成票を投じたい人のための2つ目の答えは次のとおりです。そのため、実装しているアルゴリズム(CPU集中型、IO集中型、メモリ集中型)、ハードウェア(単一CPU、マルチコア、分散スーパーコンピューター、GPGPU、FPGA)、スキル、そして最終的にはコンパイラーに依存します。 CとFortranの両方に素晴らしいコンパイラがあります。 (Fortranコンパイラがどれほど高度であるかに真剣に驚いていますが、Cコンパイラもそうです)。
PS:Fortran GUIライブラリについて多くの悪いことを言っているので、特にライブラリを除外してくれてうれしいです。 :)
FortanがCよりも大幅に高速だと聞いたことはありませんが、特定の場合には高速になると考えられます。そして、キーは、存在する言語機能ではなく、(通常)存在しない機能にあります。
例は、Cポインターです。 Cポインターはほとんどどこでも使用されますが、ポインターの問題は、コンパイラーが通常、同じ配列の異なる部分を指しているかどうかを判断できないことです。
たとえば、次のようなstrcpyルーチンを作成した場合:
strcpy(char *d, const char* s)
{
while(*d++ = *s++);
}
コンパイラは、dとsが重複する配列である可能性があるという仮定の下で動作する必要があります。そのため、配列が重複する場合に異なる結果を生成する最適化を実行できません。ご想像のとおり、これにより実行できる最適化の種類が大幅に制限されます。
[C99には、ポインターがオーバーラップしないことをコンパイラーに明示的に伝える「制限」キーワードがあることに注意してください。また、FortranにもCのセマンティクスとは異なるセマンティクスを持つポインターがありますが、ポインターはCのように遍在しません。
しかし、CとFortranの問題に戻ると、Fortranコンパイラーは(直接記述された)Cプログラムでは不可能な最適化を実行できると考えられます。ですから、私はその主張にあまり驚かないでしょう。ただし、パフォーマンスの違いはそれほど大きくないと予想しています。 [〜5-10%]
迅速かつ単純:両方とも同等に高速ですが、Fortranはより単純です。最終的に実際に高速になるのはアルゴリズムに依存しますが、いずれにしても速度に大きな違いはありません。これは、2015年にドイツのシュトゥットガルトにある高性能コンピューティングセンターで行われたFortranワークショップで学んだことです。私はFortranとCの両方で働き、この意見を共有しています。
説明:
Cは、オペレーティングシステムを記述するために設計されました。したがって、高性能コードを書くために必要な以上の自由があります。一般にこれは問題ありませんが、慎重にプログラミングしなければ、コードの速度を簡単に落とすことができます。
Fortranは科学プログラミング用に設計されました。このため、Fortranの主な目的である構文上の高速コードの記述をサポートしています。世論とは対照的に、Fortranは時代遅れのプログラミング言語ではありません。最新の標準は2010年であり、新しいコンパイラは定期的に公開されています。これは、ほとんどの高性能コードがFortranで記述されているためです。 Fortranは(Cプラグマの)コンパイラディレクティブとして最新の機能をさらにサポートします。
例:関数への入力引数として大きな構造体を指定します(fortran:サブルーチン)。関数内では引数は変更されません。
Cは、参照による呼び出しと値による呼び出しの両方をサポートしています。これは便利な機能です。この場合、プログラマーは誤って値渡しを使用する可能性があります。構造体を最初にメモリ内にコピーする必要があるため、これにより処理速度が大幅に低下します。
Fortranは参照による呼び出しのみで動作します。これにより、プログラマーは、値による呼び出し操作が本当に必要な場合、構造体を手動でコピーする必要があります。私たちの場合、fortranは、参照渡しのCバージョンと同じくらい自動的に高速になります。
FortranとCの速度の違いは、コンパイラの最適化と特定のコンパイラで使用される基礎となる数学ライブラリの機能になります。 Cよりも高速にするFortran固有の機能はありません。
とにかく、優れたプログラマーはFortranをあらゆる言語で書くことができます。
通常、FORTRANはCよりも低速です。Cでは、プログラマが手動で最適化できるハードウェアレベルのポインタを使用できます。 FORTRAN(ほとんどの場合)は、ハードウェアメモリアドレス指定ハックにアクセスできません。 (VAX FORTRANは別の話です。)私は70年代からFORTRANのオンとオフを使用しています。 (本当に。)
しかし、90年代に始まったFORTRANは、canがマルチコアプロセッサで本当に叫ぶ本質的に並列のアルゴリズムに最適化できる特定の言語構成要素を含むように進化しました。たとえば、自動ベクトル化により、複数のプロセッサがデータのベクトル内の各要素を同時に処理できます。 16プロセッサ-16要素ベクトル-処理には1/16の時間がかかります。
Cでは、独自のスレッドを管理し、マルチプロセッシング用にアルゴリズムを慎重に設計してから、一連のAPI呼び出しを使用して、並列処理が適切に行われるようにする必要があります。
FORTRANでは、マルチプロセッシング用にアルゴリズムを慎重に設計するだけです。コンパイラーとランタイムが残りを処理します。
High Performance Fortran について少し読むことができますが、多くのデッドリンクが見つかります。並列プログラミング( OpenMP.org など)と、FORTRANがそれをどのようにサポートするかについて読んでおくとよいでしょう。
高速なコードは実際には言語に依存しません。コンパイラです。ms.vbの「コンパイラ」は、「。exe」内で結び付けられた肥大化した、低速で冗長なオブジェクトコードを生成しますが、powerBasicはあまりにも生成しますより良いコード。 CおよびC++コンパイラーによって作成されたオブジェクトコードは、いくつかのフェーズ(少なくとも2)で生成されますが、設計上、ほとんどのFortranコンパイラーには、高度な最適化を含む少なくとも5つのフェーズがあるため、設計上、Fortranは常に高度に最適化されたコードを生成できます。最後に、コンパイラはあなたが求めるべき言語ではなく、私が知っている最高のコンパイラはIntel Fortranコンパイラです。なぜなら、それはLINUXとWindowsで入手でき、あなたが探しているならVSをIDEとして使用できるからですOpenWatcomでいつでも中継できる安価なコンパイラ。
これに関する詳細: http://ed-thelen.org/1401Project/1401-IBM-Systems-Journal-FORTRAN.html
Fortranには、より優れたI/Oルーチンがあります。暗黙のdo機能は、Cの標準ライブラリが対応できない柔軟性を提供します。
Fortranコンパイラーは、より複雑な構文を直接処理します。このような構文は、引数を渡す形式に簡単に変換できないため、Cでは効率的に実装できません。
Fortranは、配列、特に多次元配列を非常に便利に処理できます。 Fortranでの多次元配列の要素のスライスは、C/C++の場合よりもはるかに簡単です。 C++には、BoostやEigenなどの仕事をすることができるライブラリがありますが、それらはすべて外部ライブラリです。 Fortranでは、これらの関数は組み込みです。
Fortranの方が高速であるか、開発に便利であるかは、主に終了する必要のあるジョブに依存します。地球物理学の科学計算の人間として、私はほとんどの計算をFortranで行いました(つまり、最新のFortran、> = F90を意味します)。
最新の標準とコンパイラを使用して、いいえ!
コンパイラーはエイリアスを心配する必要がないため(最適化中により多くの仮定を立てることができるため)、FORTRANの方が高速であると提案している人もいます。ただし、restrictキーワードを含めるC99(私が思う)標準以来、これはCで処理されています。これは基本的にコンパイラに、特定のスコープ内ではポインタがエイリアスされていないことを伝えます。さらに、Cは適切なポインター演算を可能にします。この場合、エイリアスやパフォーマンスは、パフォーマンスやリソース割り当ての観点から非常に役立ちます。 FORTRANの最新バージョンでは、「適切な」ポインターの使用が可能になっていると思いますが。
最新の実装では、C全般はFORTRANよりも優れています(ただし、非常に高速です)。
http://benchmarksgame.alioth.debian.org/u64q/fortran.html
編集:
これに対する公正な批判は、ベンチマークが偏っている可能性があるということです。結果をより多くのコンテキストに配置する別のソース(Cに対して)を次に示します。
http://julialang.org/benchmarks/
ほとんどの場合、Cは通常Fortranよりも優れていることがわかります(ここでも、以下の批判を参照してください)。他の人が述べたように、ベンチマークは、ある言語を他の言語よりも優先させるために簡単にロードできる不正確な科学です。しかし、FortranとCが同様のパフォーマンスを発揮する方法をコンテキストに入れています。
これは、コンパイラーなどの品質に影響を与えるため、やや主観的です。ただし、言語/コンパイラーの観点から言えば、より直接的にあなたの質問に答えるには、Fortran over Cについて本質的にCよりも高速または優れたものになるものは何もありません。コンパイラーの品質、各言語のプログラマーのスキル、および組み込み数学は、これらの操作をサポートするライブラリーをサポートし、特定の実装でどちらが高速になるかを最終的に決定します。
編集:@Nilsなどの他の人々は、Cでのポインターの使用の違いと、おそらく最も素朴な実装をCで遅くするエイリアシングの可能性について良い点を挙げています。しかし、C99でそれを処理する方法があります、コンパイラ最適化フラグ経由、および/またはCの実際の記述方法。これについては、@ Nilsの回答と彼の回答に続く後続のコメントで詳しく説明されています。
投稿のほとんどはすでに説得力のある議論を示しているので、別の側面に2セントということわざを追加します。
最終的に処理能力の点でFortranを高速または低速にすることが重要になる場合がありますが、Fortranで何かを開発するのに5倍の時間がかかる場合:
その場合、問題は無関係です。何かが遅い場合、ほとんどの場合、一定の制限を超えて改善することはできません。もっと速くしたい場合は、アルゴリズムを変更してください。最後に、コンピューターの時間は安いです。人間の時間はそうではありません。人間の時間を短縮する選択を大切にします。コンピュータの時間が長くなれば、とにかく費用対効果が高いです。