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
wohingegen
fmin(-0.0, 0.0) = -0.0
fmax(-0.0, 0.0) = 0.0
Ist std::min
also kein 1: 1-Ersatz für fmin
. Die Funktionen std::min
und std::max
sind nicht kommutativ. Um das gleiche Ergebnis mit Doppel mit fmin
und fmax
zu 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::max
eine Teilmenge von ist fmax
.
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 Klirren 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 dafür ist std::max(double, double)
es einfach
maxsd xmm0, xmm1
Für GCC und Clang wird die Verwendung -Ofast
fmax
jedoch einfach
maxsd xmm0, xmm1
Dies zeigt also noch einmal, dass dies std::max
eine Teilmenge von ist fmax
und dass, wenn Sie ein lockereres Gleitkommamodell verwenden, das dann keine nan
Null hat oder vorzeichenbehaftet ist fmax
und std::max
dasselbe ist. Das gleiche Argument gilt offensichtlich für fmin
und std::min
.