Có một sự khác biệt quan trọng giữa std::min
, std::max
và fmin
và fmax
.
std::min(-0.0,0.0) = -0.0
std::max(-0.0,0.0) = -0.0
trong khi
fmin(-0.0, 0.0) = -0.0
fmax(-0.0, 0.0) = 0.0
Vì vậy, std::min
không phải là thay thế 1-1 cho fmin
. Các hàm std::min
và std::max
không có tính chất giao hoán. Để nhận được cùng một kết quả với các nhân đôi với fmin
và fmax
một người nên hoán đổi các đối số
fmin(-0.0, 0.0) = std::min(-0.0, 0.0)
fmax(-0.0, 0.0) = std::max( 0.0, -0.0)
Nhưng theo như tôi có thể nói tất cả các chức năng này dù sao cũng được xác định trong trường hợp này, vì vậy để chắc chắn 100%, bạn phải kiểm tra xem chúng được thực hiện như thế nào.
Có một sự khác biệt quan trọng khác. Đối với x ! = NaN
:
std::max(Nan,x) = NaN
std::max(x,NaN) = x
std::min(Nan,x) = NaN
std::min(x,NaN) = x
trong khi
fmax(Nan,x) = x
fmax(x,NaN) = x
fmin(Nan,x) = x
fmin(x,NaN) = x
fmax
có thể được mô phỏng bằng đoạn mã sau
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);
}
Điều này cho thấy đó std::max
là một tập hợp con của fmax
.
Nhìn vào assembly cho thấy Clang sử dụng mã nội trang fmax
và fmin
trong khi GCC gọi chúng từ thư viện toán học. Cụm cho tiếng kêu fmax
với -O3
là
movapd xmm2, xmm0
cmpunordsd xmm2, xmm2
movapd xmm3, xmm2
andpd xmm3, xmm1
maxsd xmm1, xmm0
andnpd xmm2, xmm1
orpd xmm2, xmm3
movapd xmm0, xmm2
trong khi đối với std::max(double, double)
nó đơn giản là
maxsd xmm0, xmm1
Tuy nhiên, đối với GCC và Clang, việc sử dụng -Ofast
fmax
trở nên đơn giản
maxsd xmm0, xmm1
Vì vậy, điều này cho thấy một lần nữa đó std::max
là một tập hợp con của fmax
và khi bạn sử dụng mô hình dấu phẩy động lỏng hơn mà không có nan
hoặc có dấu không thì fmax
và std::max
giống nhau. Đối số tương tự rõ ràng áp dụng cho fmin
và std::min
.