fmin
und fmax
sind speziell für die Verwendung mit Gleitkommazahlen (daher das "f"). Wenn Sie es für Ints verwenden, können je nach Compiler / Plattform Leistungs- oder Präzisionsverluste aufgrund von Konvertierung, Funktionsaufruf-Overhead usw. auftreten.
std::min
und std::max
sind Vorlagenfunktionen (im Header definiert <algorithm>
), die für jeden Typ mit einem <
Operator kleiner als ( ) funktionieren, sodass sie für jeden Datentyp ausgeführt werden können, der einen solchen Vergleich ermöglicht. Sie können auch Ihre eigene Vergleichsfunktion bereitstellen, wenn diese nicht funktionieren soll <
.
Dies ist sicherer, da Sie Argumente explizit konvertieren müssen, damit sie übereinstimmen, wenn sie unterschiedliche Typen haben. Mit dem Compiler können Sie beispielsweise nicht versehentlich ein 64-Bit-Int in ein 64-Bit-Float konvertieren. Allein dieser Grund sollte die Vorlagen zu Ihrer Standardauswahl machen. (Dank an Matthieu M & bk1e)
Auch wenn mit Schwimmern die Vorlage verwendet kann in der Leistung gewinnen. Ein Compiler hat immer die Möglichkeit, Aufrufe von Vorlagenfunktionen einzubinden, da der Quellcode Teil der Kompilierungseinheit ist. Manchmal ist es andererseits unmöglich , einen Aufruf einer Bibliotheksfunktion inline zu setzen (gemeinsam genutzte Bibliotheken, fehlende Optimierung der Verbindungszeit usw.).
Es gibt einen wichtigen Unterschied zwischen
std::min
,std::max
undfmin
undfmax
.std::min(-0.0,0.0) = -0.0 std::max(-0.0,0.0) = -0.0
wohingegen
fmin(-0.0, 0.0) = -0.0 fmax(-0.0, 0.0) = 0.0
Ist
std::min
also kein 1: 1-Ersatz fürfmin
. Die Funktionenstd::min
undstd::max
sind nicht kommutativ. Um das gleiche Ergebnis mit Doppel mitfmin
undfmax
zu erhalten, sollte man die Argumente austauschenfmin(-0.0, 0.0) = std::min(-0.0, 0.0) fmax(-0.0, 0.0) = std::max( 0.0, -0.0)
Soweit ich jedoch sagen kann, sind alle diese Funktionen in diesem Fall ohnehin definiert. Um 100% sicher zu sein, müssen Sie testen, wie sie implementiert sind.
Es gibt noch einen weiteren wichtigen 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
wohingegen
fmax(Nan,x) = x fmax(x,NaN) = x fmin(Nan,x) = x fmin(x,NaN) = x
fmax
kann mit dem folgenden Code emuliert werdendouble 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 dies
std::max
eine Teilmenge von istfmax
.Ein Blick auf die Assembly zeigt, dass Clang integrierten Code für
fmax
und verwendet,fmin
während GCC sie aus einer Mathematikbibliothek aufruft. Die Baugruppe zum Klirrenfmax
mit-O3
istwährend dafür ist
std::max(double, double)
es einfachFür GCC und Clang wird die Verwendung
-Ofast
fmax
jedoch einfachDies zeigt also noch einmal, dass dies
std::max
eine Teilmenge von istfmax
und dass, wenn Sie ein lockereres Gleitkommamodell verwenden, das dann keinenan
Null hat oder vorzeichenbehaftet istfmax
undstd::max
dasselbe ist. Das gleiche Argument gilt offensichtlich fürfmin
undstd::min
.quelle
_mm_max_sd
das zeigt, dass maxsd weder nan fallen lässt noch pendelt. coliru.stacked-crooked.com/a/768f6d831e79587fSie vermissen den gesamten Punkt von fmin und fmax. Es wurde in C99 aufgenommen, damit moderne CPUs ihre nativen (gelesenen SSE) Anweisungen für Gleitkomma-Min und Max verwenden und einen Test und eine Verzweigung (und damit eine möglicherweise falsch vorhergesagte Verzweigung) vermeiden können. Ich habe Code neu geschrieben, der std :: min und std :: max verwendet hat, um stattdessen SSE-Intrinsics für min und max in inneren Schleifen zu verwenden, und die Beschleunigung war signifikant.
quelle
-O3 -march=native
std::max<double>
und sogar(a>b)?a:b
alle sind einer einzelnen maxsd-Anweisung auf -O1 zugeordnet. (So erhalten Sie eine andere Behandlung von NaNs als bei -O0 ...)std :: min und std :: max sind Vorlagen. Sie können also für eine Vielzahl von Typen verwendet werden, die weniger als den Bediener bieten, einschließlich Floats, Doubles und Long Doubles. Wenn Sie also generischen C ++ - Code schreiben möchten, gehen Sie wie folgt vor:
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 betrifft, denke ich nicht
fmin
undfmax
unterscheide mich von ihren C ++ - Gegenstücken.quelle
swap
und einigen numerischen Funktionen wieabs
. Sie möchten die speziellen Swap- und Abs-Funktionen eines Typs anstelle der generischen verwenden, falls die speziellen vorhanden sind. Ich schlage vor, Herb Sutters Artikel über "Namespaces und das Interface-Prinzip" zu lesenWenn Ihre Implementierung einen 64-Bit-Integer-Typ bereitstellt, erhalten Sie möglicherweise eine andere (falsche) Antwort, wenn Sie fmin oder fmax verwenden. Ihre 64-Bit-Ganzzahlen werden in Doubles konvertiert, die (zumindest normalerweise) einen Signifikanten haben, der kleiner als 64-Bit ist. Wenn Sie eine solche Zahl in ein Doppel umwandeln, können / werden einige der niedrigstwertigen Bits vollständig verloren gehen.
Dies bedeutet, dass zwei wirklich unterschiedliche Zahlen bei der Konvertierung in double gleich sein können - und das Ergebnis ist diese falsche Zahl, die nicht unbedingt einer der ursprünglichen Eingaben entspricht.
quelle
Ich würde die C ++ min / max-Funktionen bevorzugen, wenn Sie C ++ verwenden, da sie typspezifisch sind. fmin / fmax erzwingt, dass alles in / von Gleitkomma konvertiert wird.
Außerdem funktionieren die C ++ min / max-Funktionen mit benutzerdefinierten Typen, solange Sie den Operator <für diese Typen definiert haben.
HTH
quelle
Wie Sie selbst bemerkt haben
fmin
undfmax
in C99 eingeführt wurden. Standard C ++ Bibliothek hatfmin
undfmax
funktioniert nicht. Bis die C99-Standardbibliothek (falls vorhanden) in C ++ integriert wird, werden die Anwendungsbereiche dieser Funktionen sauber getrennt. Es gibt keine Situation, in der Sie einander vorziehen müssen.Sie verwenden nur templated
std::min
/std::max
in C ++ und verwenden alles, was in C verfügbar ist.quelle
Verwenden Sie, wie Richard Corden betonte, die im Standard-Namespace definierten C ++ - Funktionen min und max. Sie bieten Typensicherheit und helfen, den Vergleich gemischter Typen (dh Gleitkomma mit Ganzzahl) zu vermeiden, was manchmal unerwünscht sein kann.
Wenn Sie feststellen, dass die von Ihnen verwendete C ++ - Bibliothek min / max ebenfalls als Makros definiert, kann dies zu Konflikten führen. Sie können dann verhindern, dass unerwünschte Makrosubstitutionen die min / max-Funktionen auf diese Weise aufrufen (beachten Sie zusätzliche Klammern):
(std::min)(x, y) (std::max)(x, y)
Denken Sie daran, dass dadurch die argumentabhängige Suche (ADL, auch Koenig-Suche genannt) effektiv deaktiviert wird , falls Sie sich auf ADL verlassen möchten.
quelle
fmin und fmax gelten nur für Gleitkomma- und Doppelvariablen.
min und max sind Vorlagenfunktionen, die den Vergleich beliebiger Typen bei einem binären Prädikat ermöglichen. Sie können auch mit anderen Algorithmen verwendet werden, um komplexe Funktionen bereitzustellen.
quelle
Verwenden Sie
std::min
undstd::max
.Wenn die anderen Versionen schneller sind, kann Ihre Implementierung Überladungen für diese hinzufügen, und Sie profitieren von Leistung und Portabilität:
template <typename T> T min (T, T) { // ... default } inline float min (float f1, float f2) { return fmin( f1, f2); }
quelle
Übrigens
cstdlib
gibt es__min
und__max
Sie können verwenden.Für weitere Informationen : http://msdn.microsoft.com/zh-cn/library/btkhtd8d.aspx
quelle
Könnte eine C ++ - Implementierung, die auf Prozessoren mit SSE-Anweisungen abzielt , nicht Spezialisierungen von std :: min und std :: max für die Typen float , double und long double bereitstellen , die das Äquivalent von fminf , fmin bzw. fminl haben?
Die Spezialisierungen würden eine bessere Leistung für Gleitkommatypen bieten, während die allgemeine Vorlage Nicht-Gleitkommatypen verarbeiten würde, ohne zu versuchen, Gleitkommatypen in Gleitkommatypen zu zwingen, wie dies bei fmin s und fmax es der Fall wäre.
quelle
Ich benutze immer die Min- und Max-Makros für Ints. Ich bin mir nicht sicher, warum jemand fmin oder fmax für ganzzahlige Werte verwenden würde.
Das große Problem bei Min und Max ist, dass sie keine Funktionen sind, auch wenn sie so aussehen. Wenn Sie etwas tun wie:
min (10, BigExpensiveFunctionCall())
Dieser Funktionsaufruf kann abhängig von der Implementierung des Makros zweimal aufgerufen werden. Daher ist es in meiner Organisation die beste Vorgehensweise, niemals min oder max mit Dingen aufzurufen, die kein Literal oder keine Variable sind.
quelle
#include <windows.h>
, erhaltenmin
undmax
als Makros definiert. Dies steht in Konflikt mitstd::min
undstd::max
, daher müssen Sie Ihre Quellen mit kompilieren#define NOMINMAX
, um die ersteren auszuschließen.#ifdef _WINDOWS #undef min
in den<algorithm>
Header eingefügt hätte.std::min
: Es akzeptiert tatsächlich zwei konstante Referenzen und gibt eine davon zurück. Normalerweise wird das vom Compiler gefaltet. Aber ich hatte einmal einestd::min( x, constval)
, woconstval
wiestatic const int constval=10;
in der Klasse definiert wurde. Und ich habe einen Linkfehler bekommen :undefined MyClass::constval
. Da muss nun die Konstante existieren, da ein Verweis darauf genommen wird. Kann mitstd::min( x, constval+0)
fmin
undfmax
, vonfminl
undfmaxl
könnte beim Vergleich von vorzeichenbehafteten und vorzeichenlosen Ganzzahlen bevorzugt werden - Sie können die Tatsache nutzen, dass der gesamte Bereich der vorzeichenbehafteten und vorzeichenlosen Zahlen und Sie müssen sich keine Gedanken über ganzzahlige Bereiche und Werbeaktionen machen.unsigned int x = 4000000000; int y = -1; int z = min(x, y); z = (int)fmin(x, y);
quelle