コーディングによる(非最適化)パフォーマンスの向上はありますか
float f1 = 200f / 2
と比較して
float f2 = 200f * 0.5
私の教授は、数年前に、浮動小数点の除算は浮動小数点の乗算よりも理由を詳しく述べないで遅いと私に言った。
このステートメントは、最新のPCアーキテクチャにも当てはまりますか?
pdate1
コメントに関しては、このケースも考慮してください。
float f1;
float f2 = 2
float f3 = 3;
for( i =0 ; i < 1e8; i++)
{
f1 = (i * f2 + i / f3) * 0.5; //or divide by 2.0f, respectively
}
更新2コメントからの引用:
[欲しい]乗算よりもハードウェアで除算が非常に複雑になる>アルゴリズム/アーキテクチャの要件を知りたい
はい、多くのCPUは1または2クロックサイクルで乗算を実行できますが、除算には常に時間がかかります(ただし、FP除算は整数除算よりも速い場合があります)。
この回答 を見ると、除算が24サイクルを超えることがあることがわかります。
除算が乗算よりもずっと長くかかるのはなぜですか?小学校に戻ったことを思い出すと、多くの同時加算で基本的に乗算を実行できることを思い出すかもしれません。除算には、同時に実行できない反復減算が必要であるため、時間がかかります。実際、一部のFPユニットは、逆近似を実行し、それを乗算することにより、除算を高速化します。それほど正確ではありませんが、やや高速です。
除算は本質的に乗算よりもはるかに遅い演算です。
実際、これはコンパイラがcannot(そして、あなたがしたくないかもしれない)浮動小数点の不正確さのために最適化するものかもしれません。次の2つのステートメント:
double d1 = 7 / 10.;
double d2 = 7 * 0.1;
not意味的に同一-0.1
はdouble
として正確に表現できないため、わずかに異なる値が使用されることになります。この場合、除算の乗算を置き換えると異なる結果が得られます。
はい。私が知っているすべてのFPUは、除算よりもはるかに高速に乗算を実行します。
ただし、最新のPCはvery高速です。また、多くの状況で違いを無視できるパイプラインアーキテクチャも含まれています。さらに、適切なコンパイラーは、最適化をオンにしてcompile timeで示した除算演算を実行します。更新された例では、適切なコンパイラーがその変換自体を実行します。
したがって、一般的にはコードを読みやすくすることを心配する必要がありますであり、コンパイラーがそれを高速にすることを心配します。その行で速度の測定に問題がある場合にのみ、速度のためにコードを変更することを心配する必要があります。コンパイラは、CPUの速度よりも高速な速度をよく認識しており、一般に、期待するよりもはるかに優れたオプティマイザーです。
2つのnビット数の乗算に必要なものを考えてください。最も簡単な方法では、1つの数値xを取得し、それをアキュムレーターに繰り返しシフトして条件付きで追加します(他の数値yのビットに基づいて)。 n回追加すると完了です。結果は2nビットに収まります。
除算では、2nビットのxとnビットのyから始めて、x/yを計算します。最も単純な方法は、長い除算ですが、バイナリ形式です。各段階で比較と減算を行い、商のビットをもう1つ取得します。これにはnステップかかります。
いくつかの違い:乗算の各ステップで必要なのは1ビットのみです。除算の各段階では、比較中にnビットを調べる必要があります。乗算の各段階は、他のすべての段階から独立しています(部分積を追加する順序は関係ありません)。分割の場合、各ステップは前のステップに依存します。これはハードウェアの大きな問題です。物事を独立して行うことができる場合、それらはクロックサイクル内で同時に発生する可能性があります。
ニュートンラプソンは、線形代数近似によりO(M(n))複雑さの整数除算を解決します。
コード内このメソッドには、10mults 9adds 2bitwiseshiftsが含まれています。
これは、除算が乗算の約12倍のCPUティックである理由を説明しています。
答えは、プログラミング対象のプラットフォームによって異なります。
たとえば、コンパイラはSIMD命令を使用するアセンブラコードを作成する必要があるため、x86の配列で多数の乗算を実行すると、除算を実行するよりもはるかに高速になります。 SIMD命令には除算がないため、乗算と除算を使用すると大幅に改善されます。