从C ++,是min
和max
优选超过fmin
和fmax
?为了比较两个整数,它们是否提供基本相同的功能?
您倾向于使用这些功能之一还是倾向于编写自己的功能(也许是为了提高效率,可移植性,灵活性等)?
笔记:
提前致谢!
Answers:
fmin
并且fmax
专门用于浮点数(因此为“ f”)。如果将其用于整数,则可能会由于转换,函数调用开销等原因而导致性能或精度损失,具体取决于您的编译器/平台。
std::min
和std::max
是模板函数(在header中定义<algorithm>
),可使用小于(<
)运算符在任何类型上使用,因此它们可以在允许进行这种比较的任何数据类型上使用。如果您不希望它起作用,还可以提供自己的比较功能<
。
这样比较安全,因为您必须显式转换参数以使其在不同类型时匹配。例如,编译器不会让您不小心将64位int转换为64位float。仅出于这个原因,应该使模板成为您的默认选择。(提供给Matthieu M&bk1e)
即使与float一起使用,模板也可能会赢得性能。编译器始终可以选择内联对模板函数的调用,因为源代码是编译单元的一部分。另一方面,有时无法内联对库函数的调用(共享库,缺少链接时间优化等)。
有一个重要区别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
不是1-1的替代品fmin
。函数std::min
和std::max
不是可交换的。为了得到与doublefmin
和相同的结果,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
:
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
IS
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
。
_mm_max_sd
该示例显示maxsd既不丢弃nan也不通勤。coliru.stacked-crooked.com/a/768f6d831e79587f
您会错过fmin和fmax的全部内容。它已包含在C99中,因此现代CPU可以将其本机(读取SSE)指令用于最小和最大浮点数,并避免进行测试和分支(因此可能会预测错误)。我已经重新编写了使用std :: min和std :: max的代码,以在内部循环中将SSE内在函数用于min和max,并且速度显着提高。
-O3 -march=native
std::max<double>
甚至(a>b)?a:b
所有映射到-O1上的单个maxsd指令。(所以您对NaN的处理与在-O0时的处理不同...)
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 ++同行不同。
swap
和编写一些数字函数abs
。如果要使用特殊的swap和abs函数,而不要使用泛型函数,则需要使用它。我建议阅读Herb Sutter关于“命名空间和接口原理”的文章:gotw.ca/publications/mill08.htm
正如Richard Corden指出的那样,请使用std名称空间中定义的C ++函数min和max。它们提供了类型安全性,并有助于避免比较混合类型(即浮点数与整数),这有时是不可取的。
如果您发现所使用的C ++库也将min / max定义为宏,则可能会引起冲突,那么您可以防止不必要的宏替换以这种方式调用min / max函数(请注意额外的括号):
(std::min)(x, y)
(std::max)(x, y)
请记住,如果您要依赖于ADL ,这将有效地禁用Argument Dependent Lookup(ADL,也称为Koenig查找)。
顺便说一句,在cstdlib
有__min
和__max
您可以使用。
有关更多信息:http : //msdn.microsoft.com/zh-cn/library/btkhtd8d.aspx
我总是将min和max宏用于int。我不确定为什么有人会使用fmin或fmax作为整数值。
min和max的最大陷阱是,即使它们看起来像它们,它们也不起作用。如果您执行以下操作:
min (10, BigExpensiveFunctionCall())
该函数调用可能会被调用两次,具体取决于宏的实现。因此,在我的组织中,最佳做法是永远不要用非文字或变量的东西调用min或max。
#include <windows.h>
,则获取min
并max
定义为宏。这将与std::min
和冲突std::max
,因此您需要使用来编译源#define NOMINMAX
以排除前者。
#ifdef _WINDOWS #undef min
在<algorithm>
标头中放一个,那会很好。节省了我的精力
std::min
:它实际上接受两个const引用,并返回其中一个。通常,编译器会将其折叠。但是我曾经有一个std::min( x, constval)
,在课堂上的constval
定义static const int constval=10;
。而且,我收到了链接错误:undefined MyClass::constval
。从那时起,由于必须引用constval,因此现在必须存在constval。可以使用std::min( x, constval+0)
fmin
在比较有符号和无符号整数时fmax
,最好使用和,fminl
和fmaxl
和--您可以利用整个有符号和无符号数字范围这一事实,而不必担心整数范围和提升。
unsigned int x = 4000000000;
int y = -1;
int z = min(x, y);
z = (int)fmin(x, y);