在C ++中使用min和max函数

从C ++, minmax优于fminfmax ? 为了比较两个整数,它们是否提供了基本相同的function?

你倾向于使用这些函数集合还是你更喜欢自己编写(也许是为了提高效率,可移植性,灵活性等)?

笔记:

  1. C ++标准模板库(STL)在标准C ++ algorithm头中声明minmax函数。

  2. C标准(C99)在标准C math.h头文件中提供了fminfmax函数。

提前致谢!

fminfmax专门用于浮点数(因此是“f”)。 如果您将它用于整数,您可能会由于转换,函数调用开销等原因而受到性能或精度损失,具体取决于您的编译器/平台。

std::minstd::max是模板函数(在头文件<algorithm>定义的),它使用小于( < )运算符的任何types,因此它们可以在允许这种比较的任何数据types上运行。 如果你不想让它工作的话,你也可以提供你自己的比较函数。

这是更安全的,因为你必须显式地将参数转换为匹配时,他们有不同的types。 例如,编译器不会让你意外地把一个64位的int转换成一个64位的float。 单独这个理由应该使模板成为您的默认select。 (感谢Matthieu M&bk1e)

即使使用浮动模板也可能赢得表演。 由于源代码是编译单元的一部分,因此编译器总是可以select内联调用模板函数。 另一方面,有时不可能内联调用库函数(共享库,缺less链接时优化等)。

std::minstd::maxfminfmax之间有一个重要的区别。

 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::minstd::max是不可交换的。 为了得到与fminfmax相同的结果,应该交换参数

 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::maxfmax一个子集。

查看程序集显示Clang使用内置代码fmaxfmin而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::maxfmax一个子集,当你使用没有nan或有符号零的宽松浮点模型时, fmaxstd::max是相同的。 相同的论点显然适用于fminstd::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 } 

至于性能,我不认为fminfmax不同于他们的C ++同行。

如果您的实现提供了64位整数types,则可能会使用fmin或fmax得到不同的(不正确的)答案。 你的64位整数将被转换为双精度,这将会(至less通常)有一个小于64位的有效数。 当你把这样的数字转换成双精度时,一些最不重要的位可能会完全丢失。

这意味着两个真正不同的数字在转换为double时可能会相等,结果将是不正确的数字,这不一定等于任何一个原始input。

如果使用C ++,我更喜欢C ++最小/最大函数,因为它们是types特定的。 fmin / fmax将强制所有内容转换为浮点数。

另外,只要你为这些types定义了operator <,那么C ++ min / max函数就可以和用户定义的types一起工作。

HTH

正如你自己所说的, fminfmax是在C99中引入的。 标准C ++库没有fminfmax函数。 直到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::minstd::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。

当比较有符号和无符号整数时, fminlfmaxl fminfmax可能是首选 – 您可以利用整个范围的有符号和无符号数字,而且您不必担心整数范围和提升。

 unsigned int x = 4000000000; int y = -1; int z = min(x, y); z = (int)fmin(x, y); 

针对具有SSE指令的处理器的C ++实现不能针对types为floatdoublelong doublestd :: minstd :: max提供专门化,分别相当于fminffminfminl

专业化会为浮点types提供更好的性能,而通用模板将处理非浮点types,而不会尝试将浮点types强制转换为fminfmax会浮动的types。