解决方案
fmin
和fmax
专门用于浮点数(因此<!>“f <!>”;)。如果将其用于整数,则可能会因转换,函数调用开销等而导致性能或精度损失,具体取决于您的编译器/平台。
std::min
和std::max
是模板函数(在标题 <algorithm>
<中定义/ a>)使用小于(<
)运算符在任何类型上工作,因此它们可以对允许这种比较的任何数据类型进行操作。如果您不希望它在<=>之外工作,您也可以提供自己的比较功能。
这更安全,因为当它们具有不同类型时必须显式转换参数以匹配。例如,编译器不会让您意外地将64位int转换为64位浮点数。仅此原因应该使模板成为您的默认选择。 (感谢Matthieu M <!> amp; 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
所以x ! = NaN
不是1-1替代-O3
。函数std::max(double, double)
和-Ofast
不可交换。要使用nan
和<=>双打来获得相同的结果,应该交换参数
fmin(-0.0, 0.0) = std::min(-0.0, 0.0)
fmax(-0.0, 0.0) = std::max( 0.0, -0.0)
但据我所知,所有这些函数是在这种情况下无论如何定义的实现,因此要100%确定你必须测试它们的实现方式。
还有另一个重要的区别。对于<=>:
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
<=>可以使用以下代码进行模拟
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);
}
这表明<=>是<=>的子集。
查看程序集显示Clang使用<=>和<=>的内置代码,而GCC从数学库中调用它们。 <=>与<=>的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
而对于<=>,它只是
maxsd xmm0, xmm1
然而,对于GCC和Clang使用<=> <=>变得简单
<*>因此,再次显示<=>是<=>的子集,并且当您使用没有<=>或符号为零的宽松浮点模型时,<=>和<=>是相同的。同样的论点显然适用于<=>和<=>。
你错过了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时,一些最低有效位可能/将完全丢失。
这意味着两个真正不同的数字在转换为double时最终会相等 - 结果将是不正确的数字,这不一定等于任何一个原始输入。
如果您使用C ++,我更喜欢C ++ min / max函数,因为它们是特定于类型的。 fmin / fmax将强制所有内容转换为浮点数。
此外,只要您定义了operator <!> lt; C ++ min / max函数将使用用户定义的类型。对于那些类型。
HTH
正如您自己所说,fmin
和fmax
是在C99中引入的。标准C ++库没有std::min
和std::max
函数。直到C99标准库被合并到C ++中(如果有的话),这些函数的应用程序区域被完全分开。在任何情况下你都不必<!>“;更喜欢<!>”;一个在另一个上面。
您只需在C ++中使用模板化<=> / <=>,并使用C中可用的任何内容。
正如Richard Corden指出的那样,使用在std命名空间中定义的C ++函数min和max。它们提供类型安全性,并有助于避免比较混合类型(即浮点数与整数)有时可能不合需要的类型。
如果您发现您使用的C ++库也将min / max定义为宏,则可能会导致冲突,那么您可以通过这种方式阻止不需要的宏替换调用min / max函数(注意额外的括号):
(std::min)(x, y)
(std::max)(x, y)
请记住,这将有效禁用 Argument Dependent Lookup (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);
}
顺便说一下,在cstdlib
中有__min
和__max
可以使用。
更多信息: http://msdn.microsoft.com/zh-cn /library/btkhtd8d.aspx
针对具有SSE指令的处理器的C ++实现无法为类型 float std :: min 和 std :: max 的特化>, double 和 long double ,相当于 fminf , fmin 和 fminl ,分别?
特殊化将为浮点类型提供更好的性能,而通用模板将处理非浮点类型而不尝试将浮点类型强制转换为浮点类型,就像 fmin 一样s和 fmax es会。
我总是使用最小和最大宏进行整数。我不确定为什么有人会使用fmin或fmax作为整数值。
最小和最大的大问题是它们不是功能,即使它们看起来像它们。如果您执行以下操作:
min (10, BigExpensiveFunctionCall())
根据宏的实现,可能会调用两次函数调用。因此,我的组织中的最佳做法是永远不要使用非文字或变量的东西来调用min或max。
fmin
fmax
和fminl
,fmaxl
和<=>可能是首选 - 您可以利用整个有符号和无符号数的范围,而不是不得不担心整数范围和促销。
unsigned int x = 4000000000;
int y = -1;
int z = min(x, y);
z = (int)fmin(x, y);