Verwendung von min und max-Funktionen in C ++
Frage
Von C ++, sind min
und max
bevorzugt über fmin
und fmax
? Für zwei ganze Zahlen zu vergleichen, haben sie grundsätzlich die gleiche Funktionalität zur Verfügung stellen?
Haben Sie neigen dazu, eine dieser Gruppen von Funktionen zu nutzen oder möchten Sie lieber Ihre eigenen (vielleicht verbessern Effizienz, Portabilität, Flexibilität, etc.) Schreiben?
Weitere Informationen:
-
Die C ++ Standard Template Library (STL) deklariert die
min
undmax
Funktionen in der Standard-C ++ Algorithmus Header. -
Der C-Standard (C99) stellt die
fmin
undfmax
Funktion in der Standard-C math .h Header.
Vielen Dank im Voraus!
Lösung
fmin
fmax
und sind speziell für die Verwendung mit Gleitkommazahlen (daher der „f“). Wenn Sie es für ints verwenden, können Sie die Leistung oder Genauigkeit Verluste erleiden aufgrund der Umwandlung, Funktionsaufruf Overhead etc. abhängig von der Compiler / Plattform.
std::min
und std::max
sind Template-Funktionen (definiert in Header <algorithm>
), die Arbeit auf jeder Art mit einem weniger-als (<
) Betreiber, so dass sie auf einem beliebigen Datentyp arbeiten, die einen solchen Vergleich ermöglicht. Sie können auch Ihre eigene Vergleichsfunktion zur Verfügung stellen, wenn Sie es <
abzuarbeiten nicht wollen.
Dies ist sicherer, da Sie müssen explizit Argumente konvertieren anpassen, wenn sie unterschiedliche Typen haben. Der Compiler lassen Sie nicht aus Versehen ein 64-Bit-int in einen 64-Bit-Float zum Beispiel konvertieren. Allein aus diesem Grund sollten die Vorlagen, um Ihre Standard-Wahl. (Credit Matthieu M & bk1e)
Auch wenn mit Schwimmern die Vorlage verwendet können in der Leistung gewinnen. Ein Compiler hat immer die Möglichkeit, inlining ruft Funktionen auf Vorlage, da der Quellcode Teil der Übersetzungseinheit ist. Manchmal ist es unmöglich einen Aufruf einer Bibliotheksfunktion Inline, auf der anderen Seite (Shared Libraries, das Fehlen von Link-Zeitoptimierung, etc.).
Andere Tipps
Es gibt einen wichtigen Unterschied zwischen std::min
, std::max
und fmin
und fmax
.
std::min(-0.0,0.0) = -0.0
std::max(-0.0,0.0) = -0.0
während
fmin(-0.0, 0.0) = -0.0
fmax(-0.0, 0.0) = 0.0
So std::min
kein Ersatz für 1-1 fmin
ist. Die Funktionen std::min
und std::max
sind nicht kommutativ. Um das gleiche Ergebnis mit Doppel mit fmin
zu bekommen und fmax
sollte man die Argumente tauschen
fmin(-0.0, 0.0) = std::min(-0.0, 0.0)
fmax(-0.0, 0.0) = std::max( 0.0, -0.0)
Aber soweit ich das sagen kann all diese Funktionen sind Implementierung ohnehin in diesem Fall definiert so 100% sicher, dass Sie testen müssen, um sein, wie sie umgesetzt werden.
Es ist ein weiterer wichtiger Unterschied. Für x ! = NaN
:
std::max(Nan,x) = NaN
std::max(x,NaN) = x
std::min(Nan,x) = NaN
std::min(x,NaN) = x
während
fmax(Nan,x) = x
fmax(x,NaN) = x
fmin(Nan,x) = x
fmin(x,NaN) = x
fmax
kann mit dem folgenden Code emuliert werden
double myfmax(double x, double y)
{
// z > nan for z != nan is required by C the standard
int xnan = isnan(x), ynan = isnan(y);
if(xnan || ynan) {
if(xnan && !ynan) return y;
if(!xnan && ynan) return x;
return x;
}
// +0 > -0 is preferred by C the standard
if(x==0 && y==0) {
int xs = signbit(x), ys = signbit(y);
if(xs && !ys) return y;
if(!xs && ys) return x;
return x;
}
return std::max(x,y);
}
Dies zeigt, dass std::max
eine Teilmenge von fmax
ist.
bei der Montage der Suche zeigt, dass Clang builtin Code für fmax
und fmin
verwendet, während GCC sie von einer Mathematik-Bibliothek aufruft. Die Anordnung für Klirren für fmax
mit -O3
ist
movapd xmm2, xmm0
cmpunordsd xmm2, xmm2
movapd xmm3, xmm2
andpd xmm3, xmm1
maxsd xmm1, xmm0
andnpd xmm2, xmm1
orpd xmm2, xmm3
movapd xmm0, xmm2
während für std::max(double, double)
es ist einfach
maxsd xmm0, xmm1
Doch für GCC und Clang mit -Ofast
fmax
wird einfach
maxsd xmm0, xmm1
Also das zeigt einmal mehr, dass std::max
ist eine Teilmenge von fmax
und dass, wenn Sie verwenden, um eine lockerere Floating-Point-Modell, das nicht nan
hat oder unterzeichnet Null dann fmax
und std::max
sind die gleichen. Das gleiche Argument gilt selbstverständlich für fmin
und std::min
.
Sie verpassen den ganzen Punkt von fmin und fmax. Es wurde in C99 enthalten, so dass moderne CPUs ihre Mutter nutzen könnten Anweisungen für Gleitkomma-min und max (SSE lesen) und einen Test und Zweig (und damit eine möglicherweise falsch vorhergesagte Verzweigung) vermeiden. Ich habe neu geschrieben Code, std :: verwendet min und std :: max SSE-Spezifika für min und max in inneren Schleifen zu verwenden, anstatt und das Speed-up war signifikant.
std :: min und std :: max sind Vorlagen. So können sie auf eine Vielzahl von Arten verwendet werden, die weniger als Betreiber, einschließlich Schwimmer, Doppel-, lange Doppelzimmer. Also, wenn Sie generische C ++ Code schreiben wollte, würden Sie etwas tun, wie folgt aus:
template<typename T>
T const& max3(T const& a, T const& b, T const& c)
{
using std::max;
return max(max(a,b),c); // non-qualified max allows ADL
}
Was die Leistung, ich glaube nicht, fmin
und fmax
von ihren C ++ Pendants unterscheiden.
Wenn Ihre Implementierung eine Art 64-Bit-Integer bietet, können Sie eine andere (falsche) Antwort erhalten, indem fmin oder fmax verwenden. Ihre 64-Bit-Integer wird verdoppelt umgewandelt werden, das wird (zumindest in der Regel) einen Signifikanden hat, die kleiner als 64 Bit ist. Wenn Sie eine solche Nummer zu einem Doppel konvertieren, können einige der am wenigsten signifikanten Bits / vollständig verloren.
Das bedeutet, dass zwei Zahlen, die wirklich anders waren gleich, wenn sie doppelt umgewandelt könnte am Ende - und das Ergebnis wird, dass eine falsche Zahl, das ist nicht unbedingt gleich entweder der ursprünglichen Eingänge
.Ich würde die C ++ min / max Funktionen bevorzugen, wenn Sie C ++ verwenden, weil sie typspezifisch sind. fmin / fmax wird alles zwingen zum / vom Gleitkomma umgewandelt werden.
Auch die C ++ min / max-Funktionen werden so lange mit benutzerdefinierten Typen arbeiten, wie Sie Operator definiert haben HTH
Wie Sie selbst bemerkt, fmin
und fmax
wurden in C99 eingeführt. Standard C ++ Bibliothek ist fmin
und fmax
nicht funktioniert haben. Bis C99-Standardbibliothek wird in C ++ integriert (wenn überhaupt) sind die Anwendungsbereiche dieser Funktionen sauber getrennt. Es gibt keine Situation, wo Sie vielleicht müssen „lieber“ einen über den anderen.
Sie verwenden nur Templat std::min
/ std::max
in C ++, und verwenden, was auch immer in C zur Verfügung.
Wie Richard Corden hingewiesen, verwenden C ++ Funktionen min und max in std Namensraum definiert. Sie bieten Typsicherheit und helfen Mischtypen zu vermeiden, zu vergleichen (das heißt float Punkt vs integer), was manchmal unerwünscht sein kann.
Wenn Sie feststellen, dass C ++ Bibliothek, die Sie min / max als Makros definiert auch, es zu Konflikten führen kann, dann können Sie unerwünschte Makroersetzung verhindern Aufruf der Min- / Max-Funktionen auf diese Weise (Hinweis zusätzliche Klammern):
(std::min)(x, y)
(std::max)(x, y)
Denken Sie daran, dies wird effektiv Argument abhängige Lookup (ADL, auch genannt Koenig-Lookup) deaktivieren im Fall möchten Sie auf ADL verlassen.
fmin und fmax sind nur für Punkt und Doppel Variablen schweben.
min und max sind Template-Funktionen, die einen Vergleich von irgendwelchen Typen erlauben, ein binäres Prädikat gegeben. Sie können auch mit anderen Algorithmen verwendet werden, um komplexe Funktionen bereitzustellen.
Mit std::min
und std::max
.
Wenn die anderen Versionen sind schneller als Ihre Implementierung Überlastungen für diese hinzufügen können, und Sie werden den Nutzen der Leistung und Mobilität erhalten:
template <typename T>
T min (T, T) {
// ... default
}
inline float min (float f1, float f2) {
return fmin( f1, f2);
}
Durch die Art und Weise, in cstdlib
gibt es __min
und __max
Sie verwenden können.
Für mehr: http://msdn.microsoft.com/zh-cn /library/btkhtd8d.aspx
kann nicht ein C ++ Implementierung für Prozessoren mit SSE-Befehlen gezielt bietet Spezialisierungen von std :: min und std :: max für Typen float , Doppel und long double , die das Äquivalent von fminf , fmin und fminl tun bzw.
Die Spezialisierungen würden für eine bessere Leistung bieten-Floating-Point-Typen, während die allgemeine Vorlage nicht-Gleitkommatypen behandeln würde, ohne zu versuchen Gleitkommatypen in Gleitkommatypen auf diese Weise der fmin zu zwingen s und fmax es tun würde.
Ich verwende die Min- und Max-Makros für ints immer. Ich bin nicht sicher, warum jemand fmin verwenden würde oder für ganzzahlige Werte fmax.
Der große Gotcha mit min und max ist, dass sie nicht funktioniert sind, auch wenn sie aussehen wie sie. Wenn Sie so etwas wie:
min (10, BigExpensiveFunctionCall())
Das Funktionsaufruf kann zweimal aufgerufen je nach Implementierung des Makros. Als solche seine beste Praxis in meinem org nie mit den Dingen min oder max aufrufen, die nicht eine wörtliche oder variabel sind.
fmin
und fmax
, von fminl
und fmaxl
könnte bevorzugt werden, wenn und ganze Zahlen ohne Vorzeichen unterzeichnet Vergleichens - Sie sich die Tatsache zunutze, dass der gesamte Bereich der mit und ohne Vorzeichen Zahlen nehmen können, und Sie müssen nicht über Integer-Bereiche und Aktionen sorgen .
unsigned int x = 4000000000;
int y = -1;
int z = min(x, y);
z = (int)fmin(x, y);