'/'または '%'の代わりにldivまたはdivを使用して2つの変数を除算/モジュラスする特別な理由はありますか?C/C++でdivやldivを使う理由は?
答えて
はい。 C99§7.20.6.2/ 2は言う:
div
、ldiv
、およびlldiv
、機能は、単一の操作でnumer/denom
とnumer % denom
を計算します。 あなたが同時に商と剰余の両方を計算したい場合は/
と%
演算子を使用するよりも速いとをはずの
。
édéric:「*より速くなると思っています」と言ったとき、時にはそうでないことを意味していますか? –
@Stuart、まったく、@ジョナサン・ウッドの答えとその後のコメントを見てください。基本的には、パフォーマンスを向上させるために 'ldiv'ファミリーの関数を使うことを考えているのであれば、コンパイラーは関数呼び出しよりも安価なもので'商+余剰 '計算を最適化するほどスマートではないと思っていますあるいは 'ldiv'とそのilkが実際の関数ではなくコンパイラの組み込み関数であることを期待しています。 –
@Stuart Golodetz:XがYよりも速くなければならないことを強制することは、YがXよりも遅くなければならないことを要求することと同じです。高速化を保証する唯一の方法は、 '/'と '%'の両方を計算するコードを見てオプティマイザがインプリメンテーションで 'ldiv'で使用する最適化を使用することを禁止することです。しかし、なぜコンパイラはそれ自体を制限すべきですか? –
考えられるのは、/と%の結果は、プロセッサ上の単一のDIV命令から判断できるということです。したがって、歴史的には、div()は両方を取得するための最適な方法を提供するために使用されます。
しかし、新しいコンパイラが/と%演算を1つの除算に最適化できることがわかりました。たとえば、私はMicrosoft Visual C++でこの最適化を見てきました。このような場合、div()は実際には利点がありませんし、実際には呼び出しがあっても遅くなることさえあります。
+1は明示的に 'それを気にしないでください。あなたのコンパイラはおそらくそれよりも賢いでしょう。今私はちょうど私の答えにイタリックを追加します;) –
私は、1つのプロセッサの命令に連続%と/演算を最適化するために十分スマートな任意のコンパイラは、div() 。 :/ –
一部のコンパイラー・オプションを* not *インライン標準ライブラリー呼び出しに設定していない限り、なぜ私はそのようなオプションが存在すると思いますか?おそらく私はCでプログラミングをしていた日に戻ってきましたか? –
短い答え:現代の環境では実際にはありません。
人々はなぜdiv
の利益が弱いのか、または存在しないのかを説明しました。 実際にはさらに悪いです:div
と友人は良い練習を傷つけるタイプカップリングを導入しています(下記の欠点のセクションを参照)。
利点:おそらくなし
としてはdiv
の代わりに、/
と%
はおそらく操作のみアセンブリレベルで一度行われていることを保証を呼び出し、他の回答で述べています。
しかし、最も近代的な文脈で:
- CPUはとてもうまく回の計算で行わ膨大な数の最も内側のループを除いて、操作を繰り返して打つ任意のパフォーマンスは、おそらくより道小さいことを数学的な操作を最適化しました他のパフォーマンスヒット(他のコードのように、キャッシュミスなど) =>
div
の便益がある場合は、それは通常無視されます。 /
と%
を使用する場合でも、現代のコンパイラは、商とそれ以外の部分を取り出して1つの除算命令を生成するだけで正しいことを行います。 =>div
の実際のメリットはありません。
欠点:DIVと友人は数字(例えばint
またはlong
)の正確なタイプ、静的に(つまり、知られている場合は、あなたのコードが明示的に長い常にint型を使用したり、特定のタイプ
にあなたのコードを結びつけます)、をint
に、ldiv
を長く使っても問題ありません。
しかし、あなたは小さな部品が不要な仮定を避けるには、プログラミングの良い練習に従うならば、あなたはすぐにdiv
とldiv
ネクタイ種類それぞれint
またはlong
のコードを使用していることを実感。反対に、/
と%
は、実際に使用されているタイプに合わせて自動的に調整され、コードクリーナーを維持します。
これは、2つの場合には特に表示されている:あなたは抽象離れて実際の型にtypedef
を使用
- から
div
も、Cで不器用です! - テンプレートを使用して実際のタイプを抽象化します。
div
はテンプレートを破ります。
例
以下のサンプルでは、「/」を使用してそのコードを示しており、div
を使用してコードや友人になるのに対し、「%」は、クリーンシンプル、かつintに縛られない、長い、長い長いまたは何でもあります不器用です。
Testing with int
my_math_func_div_WRONG says 6
my_math_func_OVERKILL says 6 // Works but overkill cast to long
my_math_func_GOOD says 6 // No div no headache.
Testing with int in long type
my_math_func_div_WRONG says 6
my_math_func_OVERKILL says 6 // Works but overkill cast to long
my_math_func_GOOD says 6 // No div no headache.
Testing with actual long
my_math_func_div_WRONG says 70503280 // FAIL
my_math_func_OVERKILL says 500000006
my_math_func_GOOD says 500000006 // No div no headache.
ソースコード:
#include <iostream>
// '/' and '%' are smart about type.
// This code is simple and will work with int, long, longlong, char, whatever.
template<typename T>
T my_math_func_GOOD(T number)
{
T quotient = number/10;
T remainder = number % 10;
// do something
return quotient + remainder;
}
// div and friends are not smart about type.
// How do you write code smart about type with them ?
// Plus adds dependency on C's stdlib.
#include <stdlib.h>
template<typename T>
T my_math_func_div_WRONG(T number)
{
// This will always downcast to int. Defeats purpose of template.
div_t result = div(number, 10);
T quotient = result.quot;
T remainder = result.rem;
// do something
return quotient + remainder;
}
template<typename T>
T my_math_func_OVERKILL(T number)
{
// This will always cast to long (up from int, OVERKILL, possibly down from long long, FAIL). Defeats purpose of template.
ldiv_t result = ldiv(number, 10);
T quotient = result.quot;
T remainder = result.rem;
// do something
return quotient + remainder;
}
template<typename T>
void my_math_func_test(T number)
{
T n;
n = my_math_func_div_WRONG(number);
std::cout << "my_math_func_div_WRONG\tsays " << n << std::endl; // writes 6
n = my_math_func_OVERKILL(number);
std::cout << "my_math_func_OVERKILL\tsays " << n << std::endl; // writes 6
n = my_math_func_GOOD(number);
std::cout << "my_math_func_GOOD\tsays " << n << std::endl; // writes 6
}
// C99 allows absence of int argc, char **argv
int main()
{
std::cout << std::endl << "Testing with int" << std::endl;
my_math_func_test<int>(42);
std::cout << std::endl << "Testing with int in long type" << std::endl;
my_math_func_test<long>(42);
std::cout << std::endl << "Testing with actual long" << std::endl;
my_math_func_test<long>(5000000042);
// std::cout << std::endl << "Testing with long long" << std::endl;
// my_math_func_test<long long>(50000000000000000042);
}
さて、これは古いですが、私はちょうどここでつまずきました。ここで最も重要な違いは、div()の結果が定義されていることです。 C標準は商を丸める方法を述べていません。これは、コンパイラがCPUに依存するマシンの実装を使用できる必要があるためです。 2つの異なる実装が存在する: - 無限に向けて丸める - 0に向かって丸める 。
div()ですが、後者を行うために指定されているため、移植性があります。
- 1. div、ldiv、lldivがテンプレートでないのはなぜですか?
- 2. linuxでserviceコマンドを使う理由は?
- 3. Makefileでexecを使う理由は?
- 4. LEFT JOINでレコードを増やす理由
- 5. node.jsでjadeや他のテンプレートを使用する理由
- 6. divが並んでいない理由
- 7. `return x == 5を使う理由は? true:false; `?
- 8. constメンバー関数を使う理由は?
- 9. lambdaなしでインラインで使う理由
- 10. 高さを使用すると、divが親divの外にある理由:100%
- 11. Spring MVCでModelクラス(model.addAttribute())を使う理由は何ですか?
- 12. Divがページにプッシュダウンされる理由
- 13. ラムダで# 'を使用する理由は?
- 14. Gtk :: TreeModel :: ColumnRecordを使う理由
- 15. パスでtry/exceptと反対にcontextlib.suppressを使う理由は?
- 16. Objective Cのコンストラクタで[super init]を使う理由は?
- 17. コンストラクタの代わりにJavaでsetterを使う理由は?
- 18. これはallocaを使う良い理由ですか?
- 19. Exit Game's Photonのようなサーバーを使う理由は?
- 20. Android Studioでエラーが発生しやすいプラグインを使用する理由
- 21. divを切り替えることができない理由
- 22. NSMatrix、NSForm - addRow - 上記の理由とそうでない理由
- 23. VueJs SPAで状態管理を使用する理由は?
- 24. ソートをソートする理由累積を使用する理由
- 25. Divは何の理由もなくドロップダウンしていますか?
- 26. シングルトンがカップリングを行う理由は?
- 27. Google Chromeでdivに折り畳まれている理由
- 28. iframeがその隣のdivとインラインでない理由
- 29. divを(cssで)ボトムアップにするには?どうやって?
- 30. Googleクラウドでパッケージや命名規則が異なる理由
ありがとうございます、http://www.cppreference.com/wiki/numeric/c/divも私のためにそれをクリアしました。商と余りが足りなかった。 – Sheraz