在C ++中使用min和max函数
从C ++, min
和max
优于fmin
和fmax
? 为了比较两个整数,它们是否提供了基本相同的function?
你倾向于使用这些函数集合还是你更喜欢自己编写(也许是为了提高效率,可移植性,灵活性等)?
笔记:
-
C ++标准模板库(STL)在标准C ++ algorithm头中声明
min
和max
函数。 -
C标准(C99)在标准C math.h头文件中提供了
fmin
和fmax
函数。
提前致谢!
fmin
和fmax
专门用于浮点数(因此是“f”)。 如果您将它用于整数,您可能会由于转换,函数调用开销等原因而受到性能或精度损失,具体取决于您的编译器/平台。
std::min
和std::max
是模板函数(在头文件<algorithm>
定义的),它使用小于( <
)运算符的任何types,因此它们可以在允许这种比较的任何数据types上运行。 如果你不想让它工作的话,你也可以提供你自己的比较函数。
这是更安全的,因为你必须显式地将参数转换为匹配时,他们有不同的types。 例如,编译器不会让你意外地把一个64位的int转换成一个64位的float。 单独这个理由应该使模板成为您的默认select。 (感谢Matthieu M&bk1e)
即使使用浮动模板也可能赢得表演。 由于源代码是编译单元的一部分,因此编译器总是可以select内联调用模板函数。 另一方面,有时不可能内联调用库函数(共享库,缺less链接时优化等)。
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%确定你必须testing它们是如何实现的。
还有一个重要的区别。 对于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从math库中调用它们。 用于-O3
fmax
的assembly是
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)指令来进行浮点最小值和最大值,并避免testing和分支(因此可能是错误预测的分支)。 我已经重写了使用std :: min和std :: max的代码,以便在内部循环中使用SSE intrinsics作为min和max,而且速度很快。
std :: min和std :: max是模板。 因此,它们可以用于提供less于运营商的各种types,包括浮动,双打,长双打。 所以,如果你想编写通用的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位整数types,则可能会使用fmin或fmax得到不同的(不正确的)答案。 你的64位整数将被转换为双精度,这将会(至less通常)有一个小于64位的有效数。 当你把这样的数字转换成双精度时,一些最不重要的位可能会完全丢失。
这意味着两个真正不同的数字在转换为double时可能会相等,结果将是不正确的数字,这不一定等于任何一个原始input。
如果使用C ++,我更喜欢C ++最小/最大函数,因为它们是types特定的。 fmin / fmax将强制所有内容转换为浮点数。
另外,只要你为这些types定义了operator <,那么C ++ min / max函数就可以和用户定义的types一起工作。
HTH
正如你自己所说的, fmin
和fmax
是在C99中引入的。 标准C ++库没有fmin
和fmax
函数。 直到C99标准库被合并到C ++中(如果曾经),这些函数的应用领域是完全分离的。 没有任何情况下,你可能不得不“偏好”一个。
你只需要在C ++中使用模板std::min
/ std::max
,并使用C中可用的任何东西。
正如Richard Corden指出的那样,使用std命名空间中定义的C ++函数min和max。 它们提供了types安全性,并且有助于避免比较混合types(即浮点与整数)有时可能不期望的情况。
如果你发现你使用的C ++库定义了最小/最大值作为macros,它可能会导致冲突,那么你可以防止不必要的macrosreplace这样调用min / max函数(注意额外的括号):
(std::min)(x, y) (std::max)(x, y)
请记住,这将有效地禁用参数依赖查找 (ADL,也称为Koenig查找),以防万一你想依靠ADL。
fmin和fmax仅用于浮点和双variables。
min和max是模板函数,允许比较任何types,给定一个二元谓词。 它们也可以与其他algorithm一起使用来提供复杂的function。
使用std::min
和std::max
。
如果其他版本更快,那么你的实现可以增加这些重载,你将得到性能和可移植性的好处:
template <typename T> T min (T, T) { // ... default } inline float min (float f1, float f2) { return fmin( f1, f2); }
顺便说一下,在cstdlib
有__min
和__max
可以使用。
更多: http : //msdn.microsoft.com/zh-cn/library/btkhtd8d.aspx
我总是使用最小和最大的macros来进行整数。 我不知道为什么有人会使用fmin或fmax作为整数值。
最小和最大的问题在于它们不是function,即使它们看起来像它们。 如果你做了这样的事情:
min (10, BigExpensiveFunctionCall())
根据macros的实现,该函数调用可能会被调用两次。 因此,在我的组织中,最好的做法是不要将最小或最大的事情称为非文字或variables。
当比较有符号和无符号整数时, fminl
和fmaxl
fmin
和fmax
可能是首选 – 您可以利用整个范围的有符号和无符号数字,而且您不必担心整数范围和提升。
unsigned int x = 4000000000; int y = -1; int z = min(x, y); z = (int)fmin(x, y);
针对具有SSE指令的处理器的C ++实现不能针对types为float , double和long double的std :: min和std :: max提供专门化,分别相当于fminf , fmin和fminl ?
专业化会为浮点types提供更好的性能,而通用模板将处理非浮点types,而不会尝试将浮点types强制转换为fmin和fmax会浮动的types。