在 C + + 中使用最小和最大函数

从 C + + 来看,std::minstd::max是否优于 fminfmax?为了比较两个整数,它们提供了基本相同的功能吗?

您是倾向于使用这些函数集中的一个,还是倾向于编写自己的函数集(也许是为了提高效率、可移植性、灵活性等) ?

备注:

  1. C + + 标准模板库(STL)在标准的 c + + 算法头中声明了 minmax函数。

  2. C 标准(C99)在标准 C 数学头中提供 fminfmax函数。

先谢谢你!

331059 次浏览

对于 int,我总是使用 min 和 max 宏。我不知道为什么有人会使用 fmin 或 fmax 作为整数值。

最大和最小的问题是,他们不是功能,即使他们看起来像他们。如果你这样做:

min (10, BigExpensiveFunctionCall())

根据宏的实现,该函数调用可能被调用两次。因此,在我的组织中,最好的做法是永远不要用不是文字或变量的东西来调用 min 或 max。

fminfmax专门用于浮点数(因此是“ f”)。如果将其用于 int,则可能会因为转换、函数调用开销等因素而导致性能或精度损失,这取决于您的编译器/平台。

std::minstd::max是模板函数(在头 <algorithm>中定义) ,它们在任何具有小于(<)运算符的类型上运行,因此它们可以在允许这种比较的任何数据类型上运行。如果您不希望它在 <上工作,也可以提供自己的比较函数。

这样做更安全,因为当参数具有不同类型时,必须显式地转换参数以进行匹配。例如,编译器不会让您意外地将64位 int 转换为64位 float。仅此一个原因就应该使模板成为您的默认选择。(贷款给 Matthieu M & bk1e)

即使与浮动模板一起使用,五月也能在性能上获胜。编译器始终可以选择内联对模板函数的调用,因为源代码是编译单元的一部分。另一方面,有时候是 不可能来内联对库函数的调用(共享库,缺少链接时间优化等等)。

如果使用 C + + ,我更喜欢 C + + 的 min/max 函数,因为它们是特定于类型的。Fmin/fmax 将强制将所有内容转换为/从浮点数。

另外,只要为用户定义的类型定义了运算符 < ,C + + min/max 函数就可以使用这些类型。

高温

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
}

至于性能,我不认为 fminfmax与 C + + 的对应物有什么不同。

Fmin 和 fmax 只适用于浮点数和双变量。

Min 和 max 是模板函数,它们允许对给定的二进制谓词进行任意类型的比较。它们还可以与其他算法一起使用,以提供复杂的功能。

正如你自己注意到的,fminfmax是在 C99中引入的。标准 C + + 库没有 fminfmax函数。在 C99标准库被合并到 C + + 中之前(如果有的话) ,这些函数的应用程序区域是完全分开的。在任何情况下,你都不必“偏爱”其中一个。

您只需在 C + + 中使用模板化的 std::min/std::max,并使用 C 中提供的任何内容。

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

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

在比较有符号和无符号整数时,fminlfmaxlfminfmax可能是首选——你可以利用整个有符号和无符号数的范围这一事实,而且你不必担心整数范围和提升。

unsigned int x = 4000000000;
int y = -1;


int z = min(x, y);
z = (int)fmin(x, y);

使用 std::minstd::max

如果其他版本的速度更快,那么您的实现可以为这些版本添加重载,并且您将获得性能和可移植性的好处:

template <typename T>
T min (T, T) {
// ... default
}


inline float min (float f1, float f2) {
return fmin( f1, f2);
}

正如 Richard Corden 所指出的,使用在 std 名称空间中定义的 C + + 函数 min 和 max。它们提供了类型安全性,并有助于避免比较混合类型(即浮点数与整数) ,有时这可能是不希望的。

如果您发现您使用的 C + + 库也将 min/max 定义为宏,这可能会导致冲突,那么您可以防止不必要的宏替换以这种方式调用 min/max 函数(请注意额外的括号) :

(std::min)(x, y)
(std::max)(x, y)

请记住,这将有效地禁用 参数依赖查找(ADL,也称为 Koenig 查找) ,以防您想依赖于 ADL。

你错过了 Fmin 和 Fmax 的全部要点。它被包含在 C99中,这样现代 CPU 就可以使用它们的本机(读取 SSE)指令来实现最小和最大浮点数,并避免测试和分支(因此可能是预测错误的分支)。我重新编写了使用 std: : min 和 std: : max 的代码,以便在内部循环中使用 SSE 内部函数来代替 min 和 max,并且加速效果显著。

顺便说一下,在 cstdlib中有 __min__max你可以使用。

更多内容: http://msdn.microsoft.com/zh-cn/library/btkhtd8d.aspx

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% 确定你必须测试它们是如何实现的,我只能告诉 在这种情况下,所有这些函数都是实现定义的


对于 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 从数学库调用它们。fmax-O3的叮当声组件为

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

针对具有 SSE 指令的处理器的 C + + 实现能否为 漂浮双倍长双杀类型提供 最小Max的专门化,这些类型分别相当于 FminfFminFminl

专门化将为浮点类型提供更好的性能,而通用模板将处理非浮点类型,而不像 FminFmaxes 那样试图强制将浮点类型转换为浮点类型。