Існує важлива різниця між std::min
, std::max
і fmin
та fmax
.
std::min(-0.0,0.0) = -0.0
std::max(-0.0,0.0) = -0.0
тоді як
fmin(-0.0, 0.0) = -0.0
fmax(-0.0, 0.0) = 0.0
Тож std::min
не є заміною 1-1 fmin
. Функції std::min
і std::max
не є комутативними. Для того, щоб отримати той же результат з двійниками з fmin
і fmax
один повинен поміняти місцями аргументи
fmin(-0.0, 0.0) = std::min(-0.0, 0.0)
fmax(-0.0, 0.0) = std::max( 0.0, -0.0)
Але, наскільки я можу зрозуміти, усі ці функції в даному випадку визначені в будь-якому випадку, щоб бути на 100% впевненим, що ви повинні перевірити, як вони реалізовані.
Є ще одна важлива різниця. Для x ! = NaN
:
std::max(Nan,x) = NaN
std::max(x,NaN) = x
std::min(Nan,x) = NaN
std::min(x,NaN) = x
тоді як
fmax(Nan,x) = x
fmax(x,NaN) = x
fmin(Nan,x) = x
fmin(x,NaN) = x
fmax
можна емулювати за допомогою наступного коду
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);
}
Це показує, що std::max
це підмножина fmax
.
Перегляд збірки показує, що Clang використовує вбудований код, fmax
а fmin
тоді як GCC викликає їх із математичної бібліотеки. Збірка для клакання для fmax
з -O3
є
movapd xmm2, xmm0
cmpunordsd xmm2, xmm2
movapd xmm3, xmm2
andpd xmm3, xmm1
maxsd xmm1, xmm0
andnpd xmm2, xmm1
orpd xmm2, xmm3
movapd xmm0, xmm2
тоді як для std::max(double, double)
цього просто
maxsd xmm0, xmm1
Однак для GCC та Clang використання -Ofast
fmax
стає просто
maxsd xmm0, xmm1
Отже, це ще раз показує, що std::max
це підмножина, fmax
і що коли ви використовуєте більш вільну модель із плаваючою комою, яка тоді не має nan
або не підписана нулем, fmax
і std::max
вони однакові. Очевидно, той самий аргумент стосується fmin
і std::min
.