从C ++开始,min
和max
优先于fmin
和fmax
吗?为了比较两个整数,它们是否提供基本相同的功能?
您是倾向于使用这些功能集中的一种还是更喜欢自己编写(可能是为了提高效率,可移植性,灵活性等)?
注意:
答案 0 :(得分:97)
fmin
和fmax
专门用于浮点数(因此为“f”)。如果将其用于整数,则可能会因转换,函数调用开销等而导致性能或精度损失,具体取决于您的编译器/平台。
std::min
和std::max
是模板函数(在标题<algorithm>
中定义),可以在任何类型上使用小于(<
)运算符,因此它们可以运行在任何允许这种比较的数据类型上。如果您不希望它在<
下工作,您也可以提供自己的比较功能。
这更安全,因为当它们具有不同类型时必须显式转换参数以匹配。例如,编译器不会让您意外地将64位int转换为64位浮点数。仅此原因应该使模板成为您的默认选择。 (感谢Matthieu M&amp; bk1e)
即使与浮动一起使用,模板 也可能 在性能上获胜。编译器始终可以选择内联对模板函数的调用,因为源代码是编译单元的一部分。有时,不可能内联对库函数的调用,另一方面(共享库,缺少链接时优化等)。
答案 1 :(得分:29)
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)
但据我所知all these functions are implementation defined anyway in this case所以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)
{
// 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从数学库中调用它们。 fmax
与-O3
的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
然而,对于使用-Ofast
fmax
的GCC和Clang变得简单
maxsd xmm0, xmm1
因此,再次显示std::max
是fmax
的一个子集,当您使用一个没有nan
或签名为零的宽松浮点模型时,{{1} }和fmax
是一样的。同样的论点显然适用于std::max
和fmin
。
答案 2 :(得分:16)
你错过了fmin和fmax的整个点。它包含在C99中,因此现代CPU可以使用其本机(读取SSE)指令来实现浮点最小值和最大值,并避免测试和分支(因此可能是错误预测的分支)。我重写了使用std :: min和std :: max的代码,在内部循环中使用SSE内部函数来获取min和max,而且加速很快。
答案 3 :(得分:6)
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 ++对应的不同。
答案 4 :(得分:6)
如果您的实现提供64位整数类型,则可以使用fmin或fmax获得不同(不正确)的答案。您的64位整数将转换为双精度数,它将(至少通常)具有小于64位的有效位数。当您将这样的数字转换为double时,一些最低有效位可能/将完全丢失。
这意味着两个真正不同的数字在转换为double时最终会相等 - 结果将是不正确的数字,不一定等于任何一个原始输入。
答案 5 :(得分:4)
如果您使用C ++,我更喜欢C ++ min / max函数,因为它们是特定于类型的。 fmin / fmax将强制所有内容转换为浮点数。
此外,只要您定义了运算符&lt; C ++ min / max函数将与用户定义的类型一起使用。对于那些类型。
HTH
答案 6 :(得分:2)
正如您所说,C99中引入了fmin
和fmax
。标准C ++库没有fmin
和fmax
函数。直到C99标准库被合并到C ++中(如果有的话),这些函数的应用程序区域被完全分开。在任何情况下,您都不必“偏好”一个而不是另一个。
您只需在C ++中使用模板化std::min
/ std::max
,并使用C中提供的任何内容。
答案 7 :(得分:2)
正如Richard Corden指出的那样,使用在std命名空间中定义的C ++函数min和max。它们提供类型安全性,并有助于避免比较混合类型(即浮点数与整数)有时可能不合需要的类型。
如果您发现您使用的C ++库也将min / max定义为宏,则可能会导致冲突,那么您可以通过这种方式阻止不需要的宏替换调用min / max函数(注意额外的括号):
(std::min)(x, y)
(std::max)(x, y)
请记住,如果您想依赖ADL,这将有效地禁用Argument Dependant Lookup(ADL,也称为Koenig查找)。
答案 8 :(得分:1)
fmin和fmax仅适用于浮点和双变量。
min和max是模板函数,允许在给定二元谓词的情况下比较任何类型。它们还可以与其他算法一起使用,以提供复杂的功能。
答案 9 :(得分:1)
使用std::min
和std::max
。
如果其他版本更快,那么您的实现可能会为这些版本添加重载,您将获得性能和可移植性的好处:
template <typename T>
T min (T, T) {
// ... default
}
inline float min (float f1, float f2) {
return fmin( f1, f2);
}
答案 10 :(得分:1)
顺便说一句,在cstdlib
中,您可以使用__min
和__max
。
答案 11 :(得分:1)
针对具有SSE指令的处理器的C ++实现无法为类型 float 提供 std :: min 和 std :: max 的特化strong>, double 和 long double ,相当于 fminf , fmin 和 fminl ,分别?
特殊化将为浮点类型提供更好的性能,而通用模板将处理非浮点类型而不尝试将浮点类型强制转换为浮点类型,就像 fmin 一样s和 fmax es会。
答案 12 :(得分:0)
我总是使用最小和最大宏进行整数。我不确定为什么有人会使用fmin或fmax作为整数值。
最小和最大的大问题是它们不是功能,即使它们看起来像它们。如果您执行以下操作:
min (10, BigExpensiveFunctionCall())
根据宏的实现,可能会调用两次函数调用。因此,我的组织中的最佳做法是永远不要使用非文字或变量的东西来调用min或max。
答案 13 :(得分:0)
fmin
和fmax
的{{1}}和fminl
可能是首选 - 您可以利用整个已签名范围的事实和无符号数字,您不必担心整数范围和促销。
fmaxl