Gibt es einen bestimmten Grund, ldiv oder div anstelle von '/' oder '%' zu verwenden, um zwei Variablen zu teilen?Warum verwenden Sie div oder ldiv in C/C++?
Antwort
Ja. §7.20.6.2 C99/2 sagt:
Die
div
,ldiv
undlldiv
, Funktionen berechnennumer/denom
undnumer % denom
in einem einzigen Vorgang.
Die ist angeblich schneller sein als die /
und %
Operatoren, wenn Sie sowohl die Quotienten und den Rest zur gleichen Zeit berechnen wollen.
édéric: Wenn du sagst "* soll * schneller sein", ist die Implikation, dass es manchmal nicht ist? –
@Stuart, absolut, siehe @ Jonathan Woods Antwort und mein anschließender Kommentar. Wenn Sie die 'ldiv'-Familie von Funktionen verwenden, um die Leistung zu erhöhen, denken Sie, dass Ihr Compiler nicht schlau genug ist, Ihre' Quotienten + Rest'-Berechnung mit etwas * billigerem * als einem Funktionsaufruf zu optimieren , oder Sie erwarten, dass 'ldiv' und seine Art Compiler intrinsics und nicht tatsächliche Funktionen sind. –
@Stuart Golodetz: Die Vorgabe, dass X schneller als Y sein muss, ist gleichbedeutend mit der Forderung, dass Y * langsamer * als X sein muss, was kein gutes Geschäft ist. Der einzige Weg, um sicherzustellen, dass es schneller ist, wäre zu verbieten, dass der Optimierer, wenn er Code sieht, der sowohl '/' als auch '%' berechnet, keine Optimierungen verwenden kann, die die Implementierung in 'ldiv' verwendet. Aber warum sollte sich ein Compiler so einschränken? –
Die Idee ist, dass die Ergebnisse von/und% aus einer einzigen DIV-Anweisung auf dem Prozessor ermittelt werden können. Daher wird div() historisch verwendet, um eine optimierte Möglichkeit zu bieten, beides zu erhalten.
Allerdings habe ich festgestellt, dass neuere Compiler in der Lage sind, eine/und% -Operation auf eine einzige Teilung zu optimieren. Zum Beispiel habe ich diese Optimierung für Microsoft Visual C++ gesehen. In diesen Fällen bietet div() wirklich keinen Vorteil und kann sogar langsam sein, wenn ein Anruf involviert ist.
+1 für eine explizite 'nicht einmal damit zu tun, ist Ihr Compiler wahrscheinlich schlauer als das sowieso '. Jetzt werde ich einfach gehen und kursiv zu meiner Antwort hinzufügen;) –
Ich würde denken, dass jeder Compiler, der schlau genug ist, um aufeinanderfolgende% und/Operationen in einem einzigen Prozessor Befehl zu optimieren, auch intelligent genug ist, um einen Aufruf an div() . :/ –
Es sei denn, Sie setzen eine Compileroption auf * nicht * Inline-Standardbibliotheksaufrufe. Warum denke ich, dass eine solche Option existiert ... vielleicht von damals, als ich in C programmiert habe? –
Kurze Antwort: nicht wirklich in einer modernen Umgebung.
Die Leute haben erklärt, warum der Nutzen von div
schwach oder gar nicht existent ist. Es ist eigentlich noch schlimmer: div
und Freunde führen Typ Kupplung, die gute Praxis verletzt (siehe Abschnitt unten).
Vorteil: wahrscheinlich kein
Wie gesagt in anderen Antworten, div
Aufruf statt /
und %
am meisten sorgt für wahrscheinlich, dass der Betrieb nur einmal auf Baugruppenebene erfolgt.
Aber in den meisten modernen Kontexten:
- Die CPU so gut mathematische Operationen optimiert, dass außer in der innersten Schleife einer Berechnung erfolgt zig Mal, jede Leistung getroffen durch Wiederholung ist wahrscheinlich viel kleiner ist als andere Performance-Hits (wie anderer Code um, Cache-Miss, etc.). => Vorteil von
div
, falls vorhanden, ist im Allgemeinen vernachlässigbar. - Auch bei Verwendung von
/
und%
machen moderne Compiler das Richtige, indem sie nur einen Divisionsbefehl erzeugen, der den Quotienten und den Rest daraus holt. => Kein tatsächlicher Nutzen fürdiv
.
Drawback: div und Freunde binden Sie den Code auf einen bestimmten Typ
Wenn die genaue Art der Zahlen (zB int
oder long
) sind statisch bekannt (das heißt, Ihr Code explizit verwendet int oder lang immer), mit div
für int
und ldiv
für lange ist in Ordnung.
Aber wenn man die gute Praxis der Programmierung in kleine Teile zu vermeiden unnötige Annahmen folgt, merkt man schnell, dass div
und ldiv
bindet die Code-Typen int
oder long
jeweils verwendet wird. Im Gegenteil, /
und %
passen sich automatisch an den tatsächlich verwendeten Typ an und halten den Code sauberer. Diese
ist besonders sichtbar in zwei Fällen:
- Sie
typedef
zu abstrahieren tatsächlichen Typen verwenden -div
ist ungeschickt auch in C! - verwenden Sie Vorlagen, um tatsächliche Typen wegzurollen -
div
schlägt Vorlagen.
Beispiel
Das folgende Beispiel zeigt, dass Code mit ‚/‘ und ‚%‘ ist sauber, einfach und nicht in int, lang gebunden, lange, lange oder was auch immer, während Code div
und Freunde werden ungeschickt.
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.
Quellcode:
#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);
}
Okay, das ist schon älter, aber ich hier nur gestolpert. Der wichtigste Unterschied ist hier: Das Ergebnis von div() ist definiert. Der C-Standard sagt nicht, wie der Quotient abgerundet wird. Das liegt daran, dass der Compiler in der Lage sein sollte, die Implementierung der Maschine zu verwenden, die von der CPU abhängt. Zwei verschiedene Implementierungen existieren: - Rundung in Richtung -Unendlichkeit - Rundung in Richtung 0 .
div(), ist jedoch angegeben, um Letzteres zu tun, und ist daher tragbar.
- 1. Warum konnte ich .cc-Datei nicht debuggen?
- 2. Welche ECMAScript-Version kann ich in Adobe Animate CC verwenden?
- 3. Verwenden von br oder div für Abschnittsunterbrechung
- 4. Erhalten Sie Untertitel "cc" für Youtube-Video
- 5. Disappearing DIV oder Div Grenze
- 6. Wenn Sie einen Kalender in HTML programmieren würden, würden Sie Table-Tags oder Div-Tags verwenden?
- 7. Warum verwenden Sie document.write?
- 8. Verwenden Sie XeTeX oder pdfTeX?
- 9. CC Vorschlagen Redundante Sorgt
- 10. Warum verwenden Sie angularfire $ destroy()?
- 11. Verwenden Sie ein DIV als Eingabe
- 12. HTML5: Warum sollte ich Abschnitt oder Artikel anstelle von div
- 13. Fortsetzung (call/cc) in Schema
- 14. Seltsame Javascript-Validierung in Dreamweaver CC
- 15. Verwenden des ODER in XPATH
- 16. Aktion "Alle stummschalten" in Animate CC
- 17. In ESS/Emacs, wie kann ich den R-Prozess-Puffer nach einem Cc Cj oder Cc Cr
- 18. Warum verwenden Sie $ {@ + "$ @"} in Shell-Skripten?
- 19. Warum verwenden wir canvas.save oder canvas.restore?
- 20. OpenCL - Warum READ_ONLY oder WRITE_ONLY Puffer verwenden
- 21. warum verwenden Sie externes Javascript?
- 22. PayPal nicht auszahlen Pay mit CC oder DC mit VitueMart
- 23. Verwenden Sie Ansicht oder Fragment in ViewPager
- 24. Verwenden Sie dies oder neu in JS?
- 25. Verwenden Sie Zeiger oder Array in Funktionsparameter
- 26. Verwenden Sie Onload oder bereit?
- 27. Verwenden Sie `__dict__` oder` vars() `?
- 28. Warum nicht 'geschützt' oder 'privat' in PHP verwenden?
- 29. Braintree gehostet Feld für zusätzliche CC
- 30. Get programmatisch cc: Schnittstellendefinition
Danke, http://www.cppreference.com/wiki/numeric/c/div hat es auch für mich geklärt. fehlte der Quotient und der Rest. – Sheraz