Es gibt einen wichtigen Unterschied zwischen std::min, std::maxund fminund fmax.
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::minalso kein 1: 1-Ersatz für fmin. Die Funktionen std::minund std::maxsind nicht kommutativ. Um das gleiche Ergebnis mit Doppel mit fminund fmaxzu erhalten, sollte man die Argumente austauschen
fmin(-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 werden
double myfmax(double x, double y)
{
int xnan = isnan(x), ynan = isnan(y);
if(xnan || ynan) {
if(xnan && !ynan) return y;
if(!xnan && ynan) return x;
return x;
}
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::maxeine Teilmenge von ist fmax.
Ein Blick auf die Assembly zeigt, dass Clang integrierten Code für fmaxund verwendet, fminwährend GCC sie aus einer Mathematikbibliothek aufruft. Die Baugruppe zum Klirren fmaxmit -O3ist
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 dafür ist std::max(double, double)es einfach
maxsd xmm0, xmm1
Für GCC und Clang wird die Verwendung -Ofast fmaxjedoch einfach
maxsd xmm0, xmm1
Dies zeigt also noch einmal, dass dies std::maxeine Teilmenge von ist fmaxund dass, wenn Sie ein lockereres Gleitkommamodell verwenden, das dann keine nanNull hat oder vorzeichenbehaftet ist fmaxund std::maxdasselbe ist. Das gleiche Argument gilt offensichtlich für fminund std::min.