「Accelerated C++」を読んでいます。 「C++ではdouble
がfloat
よりも実行速度が速い場合がある」という文を見つけました。文を読んだ後、float
とdouble
の動作について混乱しました。この点を説明してください。
ネイティブハードウェアの動作に依存します。
ハードウェアが(x86のように)doubleを実装する場合、floatはそこで拡張することによりエミュレートされ、変換には時間がかかります。この場合、doubleの方が高速です。
ハードウェアがフロートのみを実装している場合、それを使用してダブルをエミュレートするとさらに時間がかかります。この場合、フロートはより高速になります。
そして、ハードウェアがどちらも実装せず、両方をソフトウェアで実装する必要がある場合。この場合、両方とも遅くなりますが、doubleはわずかに遅くなります(少なくとも負荷とストアの操作が増えます)。
あなたが言及する引用は、おそらく最初のケースwasが与えられたx86プラットフォームに関するものです。しかし、これは一般的に当てはまりません。
この記事で完全な答えを見つけることができます:
すべてのコンピューター科学者が浮動小数点演算について知っておくべきこと
これは、以前のスタックオーバーフロースレッドからの引用です。float
およびdouble
変数がメモリ帯域幅にどのように影響するかについてです。
Doubleがfloatよりも多くのストレージを必要とする場合、データの読み取りに時間がかかります。それが素朴な答えです。最新のIA32では、データの送信元にすべて依存しています。 L1キャッシュにある場合、データが単一のキャッシュラインから来る場合、負荷は無視できます。複数のキャッシュラインにまたがる場合、わずかなオーバーヘッドがあります。 L2からの場合は時間がかかります。RAMの場合はさらに長くなります。ディスク上にある場合は時間がかかります。floatまたはdoubleの選択はそれほど重要ではありません。大量のシーケンシャルデータで小さな計算を行いたい場合は、小さなデータタイプが望ましいです。小さなデータセットで多くの計算を行うと、重要なデータタイプで大きなデータタイプを使用できます。データに非常にランダムにアクセスしている場合、データサイズの選択は重要ではありません-データはページ/キャッシュラインにロードされます。RAMから1バイトだけが必要な場合でも、32バイトが転送されます(これはこれに加えて、CPU/FPUはスーパースカラー(別名パイプライン化)になる可能性があるため、負荷に数サイクルかかる場合がありますが、CPU/FPUはビジー状態になる可能性がありますロード時間をある程度隠す他の何か(たとえば乗算)
簡単な答えは:依存する。
X87を搭載したCPUは、フロートをクランチし、同等に高速に倍増します。 SSEは1回のパスで4つのfloatまたは2つのdoubleを処理できるため、ベクトル化されたコードはfloatで高速に実行されます。
考慮すべきもう1つのことは、メモリ速度です。アルゴリズムによっては、データを待機している間にCPUが頻繁にアイドル状態になる場合があります。メモリを集中的に使用するコードは、floatを使用することで恩恵を受けますが、ALUで制限されたコードは(ベクトル化されていない限り)恩恵を受けません。
Doubleがfloatよりも速い場合、2つの基本的なケースを考えることができます。
ハードウェアはダブル演算をサポートしていますが、フロート演算はサポートしていません。そのため、フロートはソフトウェアによってエミュレートされるため、遅くなります。
あなたは本当に倍精度を必要とします。さて、とにかくフロートを使用する場合は、2つのフロートを使用して、倍の精度を得る必要があります。 floatを使用した真のdoubleのエミュレーションは、最初にfloatを使用するよりも遅くなります。
完全を期すために、フロートの逆のケースが高速になる理由もいくつか示します。あなたはあなたのケースで理由が支配している自分自身を見ることができます:
Doubleの精度を必要とせず、メモリ帯域幅に制限があり、ハードウェアがfloatのペナルティを負わない場合、floatはdoubleよりも高速です。
数字あたり半分のスペースを占有するため、メモリ帯域幅を節約します。
ダブルよりも多くのフロートを並行して処理できるプラットフォームもあります。
Intelでは、コプロセッサ(現在統合されている)が両方を同等に高速に処理しますが、他の人が指摘しているように、倍になるとメモリ帯域幅が大きくなり、ボトルネックを引き起こす可能性があります。スカラーSSE命令(64ビットのほとんどのコンパイラのデフォルト))を使用している場合、同じことが当てはまります。したがって、一般に、大量のデータセットで作業している場合を除き、大したことない。
ただし、parallel SSE命令では、1つの命令で4つの浮動小数点を処理できますが、2つの倍精度浮動小数点演算のみが許可されます。
32ビットの浮動小数点数が64ビットの倍精度(または80ビット80x87)よりも遅くなる理由は1つしかありません。そしてそれがアライメントです。それ以外に、フロートはより少ないメモリを使用します。これは一般に、アクセスの高速化、キャッシュパフォーマンスの向上を意味します。また、32ビット命令を処理するサイクルが少なくなります。 (コ)プロセッサに32ビット命令がない場合でも、64ビットレジスタで同じ速度で実行できます。ダブルはフロートよりも高速であり、v.v。であるテストケースを作成することはおそらく可能ですが、実際の統計アルゴリズムの私の測定では顕著な違いは示されませんでした。
2000000000回3.3を追加する実験では、結果は次のとおりです。
Summation time in s: 2.82 summed value: 6.71089e+07 // float
Summation time in s: 2.78585 summed value: 6.6e+09 // double
Summation time in s: 2.76812 summed value: 6.6e+09 // long double
したがって、doubleはCおよびC++でより高速でデフォルトです。より移植性が高く、すべてのCおよびC++ライブラリ関数でデフォルトです。 Alos doubleはfloatよりもかなり高い精度を持っています。
Stroustrupでさえdouble over floatを推奨しています:
「単精度、倍精度、および拡張精度の正確な意味は実装定義です。選択が重要な問題に適切な精度を選択するには、浮動小数点計算を十分に理解する必要があります。アドバイスをしたり、時間をかけて学習したり、ダブルを使って最善を尽くしたりすることを期待しています。」
おそらく、doubleの代わりにfloatを使用する必要がある唯一のケースは、最新のgccを備えた64ビットハードウェア上にある場合です。フロートが小さいため。 doubleは8バイトで、floatは4バイトです。
通常、floatは高速です。 doubleはより高い精度を提供します。ただし、3dNowやSSEなどの特別なプロセッサ拡張機能を使用すると、パフォーマンスが異なる場合があります。