82

从 C++ 开始,是std::minstd::max优先于fminfmax?对于比较两个整数,它们是否提供基本相同的功能?

您倾向于使用其中一组函数还是更喜欢编写自己的函数(也许是为了提高效率、可移植性、灵活性等)?

笔记:

  1. C++ 标准模板库 (STL)在标准 C++算法头文件中声明min和函数。max

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

提前致谢!

4

14 回答 14

119

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

std::min并且std::max是模板函数(在 header 中定义<algorithm>),它适用于具有小于 ( <) 运算符的任何类型,因此它们可以对允许此类比较的任何数据类型进行操作。如果您不希望它起作用,您也可以提供自己的比较功能<

这更安全,因为当它们具有不同类型时,您必须显式转换参数以匹配。例如,编译器不会让您意外地将 64 位 int 转换为 64 位浮点数。仅此原因就应该使模板成为您的默认选择。(归功于 Matthieu M & bk1e)

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

于 2009-10-27T16:47:40.427 回答
45

和和std::min之间有一个重要的区别。std::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不是 1-1 的替代品fmin。函数std::minstd::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)

但据我所知,在这种情况下,所有这些函数都是实现定义的,所以要 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 使用内置代码fmaxfmin而 GCC 从数学库中调用它们。clang for fmaxwith的程序集-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::max是 和 的子集,并且是相同的。同样的论点显然适用于和。fmaxnanfmaxstd::maxfminstd::min

于 2015-06-18T12:22:26.603 回答
17

您错过了 fmin 和 fmax 的全部内容。它包含在 C99 中,因此现代 CPU 可以使用其本机(读取 SSE)指令来处理浮点最小值和最大值,并避免测试和分支(因此可能是错误预测的分支)。我已经重写了使用 std::min 和 std::max 的代码,以在内部循环中使用 SSE 内在函数来代替 min 和 max,并且加速非常重要。

于 2010-11-01T16:35:44.483 回答
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
}

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

于 2009-10-27T16:49:12.153 回答
6

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

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

于 2009-10-27T16:55:18.210 回答
4

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

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

高温高压

于 2009-10-27T16:48:21.700 回答
2

正如您自己指出的那样,fminfmax在 C99 中进行了介绍。标准 C++ 库没有fminfmax功能。在 C99 标准库被合并到 C++ 之前(如果有的话),这些函数的应用领域是完全分离的。没有任何情况下您可能不得不“偏爱”其中一个。

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

于 2009-10-27T16:54:31.563 回答
2

正如 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 查找)。

于 2010-01-24T00:06:17.373 回答
1

fmin 和 fmax 仅适用于浮点和双精度变量。

min 和 max 是模板函数,允许在给定二元谓词的情况下比较任何类型。它们还可以与其他算法一起使用以提供复杂的功能。

于 2009-10-27T16:49:56.473 回答
1

使用std::minstd::max

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

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

inline float min (float f1, float f2) {
 return fmin( f1, f2);
}    
于 2009-10-27T19:14:14.217 回答
1

顺便说一句,cstdlib里面有__min__max你可以使用。

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

于 2012-03-11T15:24:36.650 回答
1

针对具有 SSE 指令的处理器的 C++ 实现不能为floatdoublelong double类型提供std::minstd::max的特化,它们分别相当于fminffminfminl吗?

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

于 2016-02-09T22:31:41.700 回答
0

我总是将 min 和 max 宏用于整数。我不确定为什么有人会使用 fmin 或 fmax 作为整数值。

min 和 max 最大的问题是它们不是函数,即使它们看起来像它们。如果您执行以下操作:

min (10, BigExpensiveFunctionCall())

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

于 2009-10-27T16:46:22.380 回答
0

fminfmax, offminlfmaxl在比较有符号和无符号整数时可能是首选 - 您可以利用有符号和无符号数字的整个范围这一事实,而不必担心整数范围和促销。

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

int z = min(x, y);
z = (int)fmin(x, y);
于 2009-10-27T17:03:42.780 回答