5

指定された int 値の分数を計算する必要がある場合は、次のように言います。

int j = 78;
int i = 5* j / 4;

これは行うよりも高速ですか:

int i = 1.25*j; // ?

もしそうなら、1回の乗算intで同時にいくつの除算を行うことができるかのように、どちらを使用するかを決定するために使用できる変換係数はありますか?float

編集:コメントは浮動小数点演算が遅くなることを明確にしていると思いますが、問題はどれくらいですか?float各乗算をN 除算で置き換える必要がある場合int、何Nがこれ以上価値がないのでしょうか?

4

3 に答える 3

5

あなたは、すべての値が動的であると言いましたが、それが違いを生んでいます。特定の値5 * j / 4の場合、整数演算は非常に高速になります。これは、ほとんどの場合、コンパイラがそれらを 2 つのシフトと 1 つの加算に最適化し、さらにj負の可能性に対処するためにいくつかの操作を行うためです。CPU がより適切に処理できる場合 (シングル サイクルの整数乗算など)、コンパイラは通常それを認識します。この種のことを最適化するコンパイラーの能力の限界は、基本的に、コンパイラーが実際には多くのことを知らない場合に、幅広い CPU ファミリ (たとえば、最小公分母の ARM コードを生成する) 用にコンパイルするときに発生します。したがって、常に適切な選択ができるとは限りません。

abがしばらくの間固定されている場合(ただし、コンパイル時には不明)、k = double(a) / b一度計算してから のint(k * x)さまざまな値を計算する方がx、のさまざまな値を計算するよりも高速になる可能性があると思います。私はそれを当てにしないでしょう。a * x / bx

すべての値が毎回異なる場合、 を計算するための浮動小数点除算と1.25それに続く浮動小数点乗算が、整数乗算とそれに続く整数除算よりも速くなるとは思えません。しかし、あなたは決して知りません、それをテストしてください。

最近のプロセッサでは、これに単純な相対的なタイミングを与えることは実際には不可能であり、実際には周囲のコードに大きく依存しています。多くの場合、コードの主なコストは「実際の」操作ではありません。それは、命令パイプラインが依存関係で停止したり、レジスタをスタックにあふれさせたり、関数呼び出しのオーバーヘッドなどの「目に見えない」ものです。この作業を行う関数をインライン化できるかどうかは、関数が実際にどのように行うかよりも簡単に違いを生む可能性があります。パフォーマンスの決定的なステートメントに関する限り、基本的に実際のコードをテストするか黙ってください。しかし、値が整数として始まる場合、それらに対して整数操作を実行する方がdouble、同じ数のdouble操作を変換して実行するよりも高速になる可能性があります。

于 2013-09-27T23:30:50.807 に答える
1

文脈から外してこの質問に答えることは不可能です。さらに、丸めやオーバーフローなど、整数演算と浮動小数点演算のプロパティにより、5*j/4一般に と同じ結果は得られません。(int) (1.25*j)

プログラムが主に整数演算を行っている場合、j浮動小数点への変換、1.25 による乗算、および整数への逆変換は、他の方法では使用されない浮動小数点ユニットを使用するため、無料である可能性があります。

あるいは、一部のプロセッサでは、オペレーティング システムが浮動小数点状態を無効としてマークする場合があります。そのため、プロセスが最初にそれを使用するときに例外が発生し、オペレーティング システムは浮動小数点レジスタ (別の値を含む) を保存します。プロセス)、プロセスのレジスタを復元または初期化し、例外から戻ります。これには、通常の命令の実行に比べて、かなりの時間がかかります。

答えは、プログラムが実行されている特定のプロセッサ モデルの特性、オペレーティング システム、コンパイラがソースをアセンブリに変換する方法、さらにはシステム上の他のプロセスが何を実行しているかによっても異なります。

5*j/4また、ほとんどの場合、 とのパフォーマンスの差は(int) (1.25*j)小さすぎて、プログラム内でそれまたはそのような操作が何度も繰り返されない限り、目立ちません。(もしそうなら、コードをベクトル化すること、つまり、多くの最新のプロセッサーの単一命令複数データ [SIMD] 機能を使用して一度に複数の操作を実行することには、大きな利点がある可能性があります。)

于 2013-09-27T23:58:48.407 に答える
0

あなたの場合、2の累乗による除算は右シフトで簡単に操作でき、x86やARMのシフトなどの多くのアーキテクチャで単一の命令で実行できるため5*j/4、はるかに高速になります。他のほとんどの場合、次のように最大で 2 つの命令が必要ですが、それでも浮動小数点乗算よりもおそらく高速です。さらに、これを行うと、 2 つの変換が必要になり、ドメイン間のデータ移動が 2 回必要になります。これは一般的に非常にコストがかかります。1.25*j5*jLEAADDj + (j >> 2)int i = 1.25*jintdouble

分数が 2 進浮動小数点で表現できない場合 ( のように3*j/10)、 int 乗算/除算を使用する方がより正確であり (浮動小数点では 0.3 は正確に 0.3 ではないため)、おそらくより高速です (コンパイラができるため)。定数による除算を乗算に変換して最適化します)


iとが浮動小数点型の場合jは、別の浮動小数点値を掛けた方が速い場合があります。上で述べたように、float ドメインと int ドメイン間の値の移動には時間がかかり、int と float 間の変換にも時間がかかるためです。

重要な違いは、5*j/4j が大きすぎるとオーバーフローしますが、オーバーフロー1.25*jしないことです。

とはいえ、特定のアーキテクチャと特定のコンテキストに依存するため、「どちらが速いか」と「どれだけ速いか」という質問に対する一般的な答えはありません。システムで測定して決定する必要があります。しかし、式が多くの値に対して繰り返し実行される場合は、SIMD に移行する時が来ました。

こちらもご覧ください

于 2013-09-28T01:04:32.663 に答える