Gibt es einen bestimmten Grund, ldiv oder div anstelle von „https://stackoverflow.com/“ oder „%“ zu verwenden, um zwei Variablen zu dividieren/modulieren?
Warum div oder ldiv in C/C++ verwenden?
Ja. C99 §7.20.6.2/2 sagt:
Das
div
,ldiv
undlldiv
Funktionen berechnennumer / denom
undnumer %
in einem einzigen Arbeitsgang.
denom
-
Vielen Dank, cpreference.com/wiki/numeric/c/div hat es bei mir auch geklärt. fehlte Quotient und Rest.
– Sheraz
30. Dezember 2010 um 18:46 Uhr
Jonathan Holz
Die Idee ist, dass die Ergebnisse von / und % von einem einzigen DIV-Befehl auf dem Prozessor bestimmt werden können. Historisch gesehen wird also div() verwendet, um einen optimierten Weg zu bieten, beides zu erhalten.
Ich habe jedoch festgestellt, dass neuere Compiler sowieso in der Lage sind, eine /- und %-Operation in eine einzige Division zu optimieren. Ich habe diese Optimierung zum Beispiel bei Microsoft Visual C++ gesehen. In diesen Fällen bietet div() wirklich keinen Vorteil und kann sogar langsamer sein, wenn es sich um einen Anruf handelt.
-
+1 für eine explizite
don't even bother with that, your compiler's probably smarter than that anyway
. Jetzt gehe ich einfach und füge meiner Antwort Kursivschrift hinzu;)– Frédéric Hamidi
30. Dezember 2010 um 18:59 Uhr
-
Ich würde denken, dass jeder Compiler, der intelligent genug ist, um aufeinanderfolgende %- und /-Operationen in eine einzelne Prozessoranweisung zu optimieren, auch intelligent genug ist, um einen Aufruf von div() einzufügen. :/
– Karl Knechtel
30. Dezember 2010 um 19:37 Uhr
-
Es sei denn, Sie setzen eine Compiler-Option auf nicht Inline-Standardbibliotheksaufrufe. Warum glaube ich, dass es eine solche Option gibt … vielleicht aus der Zeit, als ich noch in C programmiert habe?
– Präsident James K. Polk
30. Dezember 2010 um 19:40 Uhr
-
@Karl: Nur weil ein Compiler intelligent genug ist, um einen Aufruf einzufügen, bedeutet das nicht unbedingt, dass er konfiguriert ist oder sogar in allen Fällen dazu in der Lage ist. Jedenfalls hatte ich geglaubt, das mit “darf” und “wenn” abgedeckt zu haben.
– Jonathan Holz
30. Dezember 2010 um 22:18 Uhr
Frédéric Hamidi
Das ist soll schneller zu sein als mit dem /
und %
Operatoren, wenn Sie sowohl den Quotienten als auch den Rest gleichzeitig berechnen möchten.
-
édéric: Wenn du sagst “soll schneller zu sein”, bedeutet das, dass es manchmal nicht so ist?
– Stuart Golodetz
30. Dezember 2010 um 19:05 Uhr
-
@Stuart, absolut, siehe die Antwort von @Jonathan Wood und meinen nachfolgenden Kommentar. Grundsätzlich, wenn Sie erwägen, die
ldiv
Familie von Funktionen, um die Leistung zu steigern, denken Sie, dass Ihr Compiler nicht schlau genug ist, um Ihre zu optimierenquotient+remainder
Berechnung mit etwas billiger als ein Funktionsaufruf, oder Sie erwarten dasldiv
und ihresgleichen sind Compiler-Intrinsics und keine eigentlichen Funktionen.– Frédéric Hamidi
30. Dezember 2010 um 19:09 Uhr
-
@Stuart Golodetz: Das Vorschreiben, dass X schneller sein muss als Y, ist dasselbe wie das Vorschreiben, dass Y sein muss Langsamer als X, was kein gutes Geschäft ist. Die einzige Möglichkeit, sicherzustellen, dass es schneller ist, wäre, dem Optimierer zu verbieten, Code zu sehen, der beides berechnet
/
und%
daran zu hindern, Optimierungen zu verwenden, in denen die Implementierung verwendet wirdldiv
. Aber warum sollte sich ein Compiler so einschränken?– Steve Jessop
30. Dezember 2010 um 19:29 Uhr
-
édéric, @Steve: Danke an beide, macht Sinn 🙂
– Stuart Golodetz
30. Dezember 2010 um 22:40 Uhr
Kurze Antwort: nicht wirklich in einer modernen Umgebung.
Die Leute haben erklärt, warum davon profitieren div
ist schwach oder gar nicht vorhanden.
Es ist eigentlich noch schlimmer: div
und Freunde führen eine Typkopplung ein, was der guten Praxis schadet (siehe Abschnitt über Nachteile unten).
Vorteil: wahrscheinlich keiner
Wie in anderen Antworten gesagt, anrufen div
Anstatt von /
und %
stellt höchstwahrscheinlich sicher, dass die Operation nur einmal auf Baugruppenebene durchgeführt wird.
Aber in den meisten modernen Kontexten:
- Die CPU hat mathematische Operationen so gut optimiert, dass außer in der innersten Schleife einer Berechnung, die zigfach durchgeführt wurde, jede Leistungseinbuße durch die Wiederholung der Operation wahrscheinlich viel kleiner ist als andere Leistungseinbußen (wie anderer Code in der Nähe, Cache-Fehler usw.). => Nutzen von
div
falls vorhanden, ist im Allgemeinen vernachlässigbar. - Auch beim Benutzen
/
und%
Moderne Compiler machen sowieso das Richtige, indem sie nur einen Divisionsbefehl generieren, der Quotient und Rest daraus holt. => Kein tatsächlicher Nutzen fürdiv
.
Nachteil: div und Freunde binden Ihren Code an einen bestimmten Typ
Wenn der genaue Typ der Nummern (z int
oder long
) statisch bekannt sind (d. h. Ihr Code verwendet explizit immer int oder long), using div
zum int
und ldiv
lange ist ok.
Aber wenn Sie der guten Praxis folgen, in kleinen Teilen zu programmieren und unnötige Annahmen zu vermeiden, werden Sie dies schnell feststellen div
und ldiv
bindet den Code an Typen int
oder long
beziehungsweise. Andererseits, /
und %
passt sich automatisch an den Typ an, der im vorliegenden Fall tatsächlich verwendet wird, wodurch der Code sauberer bleibt.
Dies wird besonders in zwei Fällen sichtbar:
- Sie nutzen
typedef
tatsächliche Typen abstrahieren —div
ist sogar in C ungeschickt! - Sie verwenden Vorlagen, um tatsächliche Typen zu abstrahieren —
div
besiegt Vorlagen.
Beispiel
Das folgende Beispiel zeigt, dass Code, der „https://stackoverflow.com/“ und „%“ verwendet, sauber, einfach und nicht an int, long, long long oder was auch immer gebunden ist, während Code using 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>
// "https://stackoverflow.com/" 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 älter, aber ich bin gerade hierher gestolpert. Der wichtigste Unterschied hierbei ist: Das Ergebnis von div() ist definiert. Der C-Standard sagt nicht, wie der Quotient zu runden ist. Das liegt daran, dass der Compiler in der Lage sein sollte, die Implementierung der Maschine zu verwenden, die von der CPU abhängt. Es gibt zwei verschiedene Implementierungen: – Rundung gegen -unendlich – Rundung gegen 0 .
div() ist jedoch für Letzteres spezifiziert und daher portabel.
-
Würdest du einen Link geben, um das zu beweisen?
– mja
9. November 2018 um 14:09 Uhr
-
Seit C99: “Wenn ganze Zahlen dividiert werden, ist das Ergebnis des Operators / der algebraische Quotient, wobei jeder Bruchteil verworfen wird”.
– chux – Wiedereinsetzung von Monica
12. Januar 2019 um 17:48 Uhr
-
Würdest du einen Link geben, um das zu beweisen?
– mja
9. November 2018 um 14:09 Uhr
-
Seit C99: “Wenn ganze Zahlen dividiert werden, ist das Ergebnis des Operators / der algebraische Quotient, wobei jeder Bruchteil verworfen wird”.
– chux – Wiedereinsetzung von Monica
12. Januar 2019 um 17:48 Uhr
Mögliches Duplikat von Was ist der Zweck der Bibliotheksfunktion div()?
– mja
10. November 2018 um 3:09 Uhr