[英]Use of min and max functions in C++
fmin
和fmax
專門用於浮點數(因此稱為“f”)。 如果您將它用於整數,您可能會因轉換、函數調用開銷等而遭受性能或精度損失,具體取決於您的編譯器/平台。
std::min
和std::max
是模板函數(在頭文件<algorithm>
定義),它們適用於具有小於 ( <
) 運算符的任何類型,因此它們可以對任何允許進行此類比較的數據類型進行操作。 如果您不想讓<
起作用,您也可以提供自己的比較函數。
這更安全,因為當參數具有不同類型時,您必須顯式轉換參數以匹配。 例如,編譯器不會讓您意外地將 64 位 int 轉換為 64 位浮點數。 僅此原因就應該使模板成為您的默認選擇。 (歸功於 Matthieu M & bk1e)
即使與浮動一起使用,模板也可能在性能上獲勝。 編譯器始終可以選擇內聯對模板函數的調用,因為源代碼是編譯單元的一部分。 另一方面,有時不可能內聯對庫函數的調用(共享庫、缺少鏈接時優化等)。
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
不是fmin
的 1-1 替代品。 函數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
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)
{
// 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);
}
這表明std::max
是fmax
的子集。
查看程序集表明,Clang 使用內置代碼來表示fmax
和fmin
而 GCC 從數學庫中調用它們。 帶有-O3
fmax
clang 程序集是
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
。
您錯過了 fmin 和 fmax 的全部內容。 它包含在 C99 中,以便現代 CPU 可以使用其原生(讀取 SSE)指令進行浮點最小值和最大值,並避免測試和分支(因此可能是錯誤預測的分支)。 我已經重新編寫了使用 std::min 和 std::max 的代碼,而是在內部循環中使用 SSE 內在函數的 min 和 max ,並且加速非常顯着。
std::min 和 std::max 是模板。 因此,它們可用於提供小於運算符的各種類型,包括浮點數、雙精度數、長雙精度數。 因此,如果您想編寫通用的 C++ 代碼,您可以這樣做:
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
}
至於性能,我認為fmin
和fmax
與它們的 C++ 對應物沒有區別。
如果您的實現提供 64 位整數類型,您可能會通過使用 fmin 或 fmax 得到不同(不正確)的答案。 您的 64 位整數將轉換為雙精度數,這將(至少通常)具有小於 64 位的有效數。 當您將這樣的數字轉換為雙精度數時,一些最低有效位可能/將完全丟失。
這意味着兩個真正不同的數字在轉換為 double 時最終可能相等——結果將是那個不正確的數字,它不一定等於原始輸入中的任何一個。
如果您使用 C++,我更喜歡 C++ min/max 函數,因為它們是特定於類型的。 fmin/fmax 將強制將所有內容轉換為浮點數/從浮點數轉換。
此外,只要您為這些類型定義了 operator<,C++ min/max 函數就可以使用用戶定義的類型。
HTH
正如您自己指出的那樣, fmin
和fmax
是在 C99 中引入的。 標准 C++ 庫沒有fmin
和fmax
函數。 在 C99 標准庫被並入 C++(如果有的話)之前,這些函數的應用領域是完全分開的。 在任何情況下,您都可能不得不“偏愛”一個而不是另一個。
您只需在 C++ 中使用模板化std::min
/ std::max
,並使用 C 中可用的任何內容。
正如 Richard Corden 所指出的,使用 std 命名空間中定義的 C++ 函數 min 和 max。 它們提供類型安全,並有助於避免比較混合類型(即浮點與整數)有時可能是不受歡迎的。
如果你發現你使用的 C++ 庫也將 min/max 定義為宏,它可能會導致沖突,那么你可以防止不需要的宏替換以這種方式調用 min/max 函數(注意額外的括號):
(std::min)(x, y)
(std::max)(x, y)
請記住,這將有效地禁用參數相關查找(ADL,也稱為 Koenig 查找),以防您想依賴 ADL。
fmin 和 fmax 僅適用於浮點和雙變量。
min 和 max 是允許比較任何類型的模板函數,給定一個二元謂詞。 它們還可以與其他算法一起使用以提供復雜的功能。
使用std::min
和std::max
。
如果其他版本更快,那么您的實現可以為這些添加重載,您將獲得性能和可移植性的好處:
template <typename T>
T min (T, T) {
// ... default
}
inline float min (float f1, float f2) {
return fmin( f1, f2);
}
針對具有 SSE 指令的處理器的 C++ 實現不能為float 、 double和long double類型提供std::min和std::max 的特化,它們分別相當於fminf 、 fmin和fminl嗎?
特化將為浮點類型提供更好的性能,而通用模板將處理非浮點類型,而不會像fmin s 和fmax es 那樣試圖將浮點類型強制轉換為浮點類型。
順便說一下,在cstdlib
有__min
和__max
你可以使用。
更多信息: http : //msdn.microsoft.com/zh-cn/library/btkhtd8d.aspx
我總是對整數使用 min 和 max 宏。 我不確定為什么有人會使用 fmin 或 fmax 作為整數值。
min 和 max 的最大問題是它們不是函數,即使它們看起來像它們。 如果您執行以下操作:
min (10, BigExpensiveFunctionCall())
根據宏的實現,該函數調用可能會被調用兩次。 因此,它在我的組織中的最佳實踐是永遠不要使用不是文字或變量的東西調用 min 或 max。
在比較有符號和無符號整數時, fminl
和fmaxl
fmin
和fmax
可能是首選 - 您可以利用整個范圍的有符號和無符號數字這一事實,而不必擔心整數范圍和提升。
unsigned int x = 4000000000;
int y = -1;
int z = min(x, y);
z = (int)fmin(x, y);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.