std::min/std::max 和 fmin/fmax 有什么区别?

发布于 2024-08-08 21:50:45 字数 892 浏览 7 评论 0原文

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

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

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

  2. C 标准 (C99) 提供了标准 C 中的 fminfmax 函数math.h 标头(在 C++11 中也提供为 std::fmincmath a> 标题)。

In C++, are std::min and std::max preferable over fmin and fmax? For comparing two integers, do they provide basically the same functionality?

Do you tend to use one of these sets of functions or do you prefer to write your own (perhaps to improve efficiency, portability, flexibility, etc.)?

Notes
  1. The C++ Standard Template Library (STL) declares the min and max functions in the standard C++ algorithm header.

  2. The C standard (C99) provides the fmin and fmax function in the standard C math.h header (also provided in C++11 as std::fmin and std::fmax in the cmath header).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

故乡的云 2024-08-15 21:50:45

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

std::minstd::max 是模板函数(在标头 ) 适用于任何带有小于 (<) 运算符的类型,因此它们可以对任何允许进行此类比较的数据类型进行操作。如果您不希望它在 < 之外工作,您也可以提供自己的比较函数。

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

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

fmin and fmax are specifically for use with floating point numbers (hence the "f"). If you use it for ints, you may suffer performance or precision losses due to conversion, function call overhead, etc. depending on your compiler/platform.

std::min and std::max are template functions (defined in header <algorithm>) which work on any type with a less-than (<) operator, so they can operate on any data type that allows such a comparison. You can also provide your own comparison function if you don't want it to work off <.

This is safer since you have to explicitly convert arguments to match when they have different types. The compiler won't let you accidentally convert a 64-bit int into a 64-bit float, for example. This reason alone should make the templates your default choice. (Credit to Matthieu M & bk1e)

Even when used with floats the template may win in performance. A compiler always has the option of inlining calls to template functions since the source code is part of the compilation unit. Sometimes it's impossible to inline a call to a library function, on the other hand (shared libraries, absence of link-time optimization, etc.).

失眠症患者 2024-08-15 21:50:45

std::minstd::max 以及 fminfmax 之间存在重要区别。

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

So 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)
{
    // after the next two comparisons, x and y are equivalent or there is NaN
    if(x < y)           return y;
    if(y < x)           return x;
    // z > nan for z != nan is required by C the standard
    if(std::isnan(x))   return y;
    if(std::isnan(y))   return x;
    // +0 > -0 is preferred by C the standard
    if(std::signbit(x)) return y;
    else                return x;
}

std::maxfmax 的子集,因为它只需要第一个比较 (x < y)。

查看程序集可以发现,Clang 使用 fmaxfmin 的内置代码,而 GCC 从数学库中调用它们。带有 -O3fmax 的 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

但是,对于 GCC 和Clang 使用 -Ofast fmax 变得简单

maxsd   xmm0, xmm1

所以这再次表明 std::maxfmax 的子集当您使用没有 nan 或符号零的宽松浮点模型时,fmax 和 std::max 是相同的。同样的论点显然也适用于 fminstd::min

There is an important difference between std::min, std::max and fmin and fmax.

std::min(-0.0,0.0) = -0.0
std::max(-0.0,0.0) = -0.0

whereas

fmin(-0.0, 0.0) = -0.0
fmax(-0.0, 0.0) =  0.0

So std::min is not a 1-1 substitute for fmin. The functions std::min and std::max are not commutative. To get the same result with doubles with fmin and fmax, one should swap the arguments

fmin(-0.0, 0.0) = std::min(-0.0,  0.0)
fmax(-0.0, 0.0) = std::max( 0.0, -0.0)

But as far as I can tell all these functions are implementation defined anyway in this case so to be 100% sure you have to test how they are implemented.


There is another important difference. For x ! = NaN:

std::max(Nan,x) = NaN
std::max(x,NaN) = x
std::min(Nan,x) = NaN
std::min(x,NaN) = x

whereas

fmax(Nan,x) = x
fmax(x,NaN) = x
fmin(Nan,x) = x
fmin(x,NaN) = x

fmax can be emulated with the following code

double myfmax(double x, double y)
{
    // after the next two comparisons, x and y are equivalent or there is NaN
    if(x < y)           return y;
    if(y < x)           return x;
    // z > nan for z != nan is required by C the standard
    if(std::isnan(x))   return y;
    if(std::isnan(y))   return x;
    // +0 > -0 is preferred by C the standard
    if(std::signbit(x)) return y;
    else                return x;
}

std::max is a subset of fmax because it only needs the first comparison (x < y).

Looking at the assembly shows that Clang uses builtin code for fmax and fmin whereas GCC calls them from a math library. The assembly for clang for fmax with -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

whereas for std::max(double, double) it is simply

maxsd   xmm0, xmm1

However, for GCC and Clang using -Ofast fmax becomes simply

maxsd   xmm0, xmm1

So this shows once again that std::max is a subset of fmax and that when you use a looser floating point model which does not have nan or signed zero then fmax and std::max are the same. The same argument obviously applies to fmin and std::min.

茶花眉 2024-08-15 21:50:45

您错过了 fmin 和 fmax 的全部要点。它包含在 C99 中,以便现代 CPU 可以使用其本机(读取 SSE)指令来计算浮点最小值和最大值,并避免测试和分支(从而避免可能错误预测的分支)。我重写了使用 std::min 和 std::max 的代码,以在内部循环中使用 SSE 内在函数来表示 min 和 max,并且加速效果显着。

You're missing the entire point of fmin and fmax. It was included in C99 so that modern CPUs could use their native (read SSE) instructions for floating point min and max and avoid a test and branch (and thus a possibly mis-predicted branch). I've re-written code that used std::min and std::max to use SSE intrinsics for min and max in inner loops instead and the speed-up was significant.

酒绊 2024-08-15 21:50:45

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++ 对应的代码没有什么不同。

std::min and std::max are templates. So, they can be used on a variety of types that provide the less than operator, including floats, doubles, long doubles. So, if you wanted to write generic C++ code you'd do something like this:

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
}

As for performance, I don't think fmin and fmax differ from their C++ counterparts.

甜尕妞 2024-08-15 21:50:45

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

这意味着两个完全不同的数字在转换为 double 时可能最终相等 - 结果将是错误的数字,不一定等于任何一个原始输入。

If your implementation provides a 64-bit integer type, you may get a different (incorrect) answer by using fmin or fmax. Your 64-bit integers will be converted to doubles, which will (at least usually) have a significand that's smaller than 64-bits. When you convert such a number to a double, some of the least significant bits can/will be lost completely.

This means that two numbers that were really different could end up equal when converted to double -- and the result will be that incorrect number, that's not necessarily equal to either of the original inputs.

剪不断理还乱 2024-08-15 21:50:45

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

此外,只要您定义了运算符<,C++ min/max 函数就可以使用用户定义的类型。对于那些类型。

华泰

I would prefer the C++ min/max functions, if you are using C++, because they are type-specific. fmin/fmax will force everything to be converted to/from floating point.

Also, the C++ min/max functions will work with user-defined types as long as you have defined operator< for those types.

HTH

提笔书几行 2024-08-15 21:50:45

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

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

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

记住,这将有效禁用 < a href="http://en.wikipedia.org/wiki/Argument_dependent_name_lookup" rel="nofollow noreferrer">参数相关查找(ADL,也称为 Koenig 查找),以防您想依赖 ADL。

As Richard Corden pointed, use C++ functions min and max defined in std namespace. They provide type safety, and help to avoid comparing mixed types (i.e. float point vs integer) what sometimes may be undesirable.

If you find that C++ library you use defines min/max as macros as well, it may cause conflicts, then you can prevent unwanted macro substitution calling the min/max functions this way (notice extra brackets):

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

Remember, this will effectively disable Argument Dependant Lookup (ADL, also called Koenig lookup), in case you want to rely on ADL.

黯然 2024-08-15 21:50:45

正如您自己所指出的,fminfmax 是在 C99 中引入的。标准 C++ 库没有 fminfmax 函数。在 C99 标准库并入 C++ 之前(如果有的话),这些函数的应用领域是完全分开的。在任何情况下,您都可能必须“偏爱”其中一种而不是另一种。

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

As you noted yourself, fmin and fmax were introduced in C99. Standard C++ library doesn't have fmin and fmax functions. Until C99 standard library gets incorporated into C++ (if ever), the application areas of these functions are cleanly separated. There's no situation where you might have to "prefer" one over the other.

You just use templated std::min/std::max in C++, and use whatever is available in C.

私藏温柔 2024-08-15 21:50:45

顺便说一句,在 cstdlib 中,您可以使用 __min__max

有关更多信息: http://msdn.microsoft.com/zh-cn/library/ btkhtd8d.aspx

By the way, in cstdlib there are __min and __max you can use.

For more: http://msdn.microsoft.com/zh-cn/library/btkhtd8d.aspx

卷耳 2024-08-15 21:50:45

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

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

fmin and fmax are only for floating point and double variables.

min and max are template functions that allow comparison of any types, given a binary predicate. They can also be used with other algorithms to provide complex functionality.

墨离汐 2024-08-15 21:50:45

使用 std::minstd::max

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

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

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

Use std::min and std::max.

If the other versions are faster then your implementation can add overloads for these and you'll get the benefit of performance and portability:

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

inline float min (float f1, float f2) {
 return fmin( f1, f2);
}    
蓝海似她心 2024-08-15 21:50:45

针对具有 SSE 指令的处理器的 C++ 实现无法为 float、< strong>double 和 long double 相当于 fminffminfminl , 分别?

专业化将为浮点类型提供更好的性能,而通用模板将处理非浮点类型,而不会尝试将浮点类型强制转换为浮点类型,即 fmin 和 < fmax 会。

Couldn't a C++ implementation targeted for processors with SSE instructions provide specializations of std::min and std::max for types float, double, and long double which do the equivalent of fminf, fmin, and fminl, respectively?

The specializations would provide better performance for floating-point types while the general template would handle non-floating-point types without attempting to coerce floating-point types into floating-point types that way the fmins and fmaxes would.

℡Ms空城旧梦 2024-08-15 21:50:45

简而言之,std::max 库中的一个“通用函数”,它只是根据 < 来选择两个参数中较小的一个。 运算符,而 std::fmax 特定于浮点数,并将 NaN 视为缺失数据。

std::fmax/std::fmin

头文件的内容和含义与C标准库头文件相同[...]

- C++23 标准:[cmath.syn] p1

如果只有一个参数为 NaN,则 fmax 函数返回另一个参数(如果两个参数均为 NaN,则函数返回NaN)。
[...]
fmax 函数的主体可能是

{ return (isgreaterequal(x, y) || isnan(y)) ? x : y; }

- C17 标准:F.10.9 .2 fmax 函数

还值得注意的是,fmax/fmin 可能对零的符号敏感:

理想情况下,fmax 对零的符号敏感,例如 fmax(−0.0, +0.0) 将返回 +0 ;然而,在软件中实现可能不切实际。

- C17 标准:脚注 380

std::max/std ::分钟

模板;
constexpr const T& max(const T&a, const T&b);
// [...]

先决条件:对于第一种形式,T满足Cpp17LessThanComparable要求(表29)。

返回: 较大的值。当参数相等时返回第一个参数。

- [alg.min.max] std::max

标准中没有示例实现,但可能的实现如下所示:

{ return a < b ? b : a; }

选择哪一个

出于性能原因,最好使用 std::max 和 <代码>std::min。
在现代 x86_64 上,std::max 编译为单个指令

vmaxss  xmm0, xmm1, xmm0            ; xmm0 = max(xmm1, xmm0)

...而 std::fmax 编译为

vmaxss      xmm2, xmm1, xmm0        ; xmm2 = max(xmm1, xmm0)
vcmpunordss xmm0, xmm0, xmm0        ; test xmm0 for NaN, set mask bits
vblendvps   xmm0, xmm2, xmm1, xmm0  ; xmm0 = isnan(xmm0) ? xmm1 : xmm2

参见 编译器资源管理器

如果操作数不可能为 NaN,则应选择 std::max/std::min。否则,使用std::fmax/std::fmin

关于汇编的进一步说明

std::fmax(x, y) 不能仅使用 vmaxss dest, y, x 实现,因为如果 x 或 < code>y 为 NaN,dest = xstd::fmax 选择 xy,具体取决于哪一个不是 NaN。 vmaxss 在所有可能的方面都偏向于 x

但是,vmaxssx x 的行为相匹配。是吗? y : xstd::max 完全一样。

In short, std::max is a "generic function" from the <algotithm> library that simply chooses the lower of two arguments according to the < operator, whereas std::fmax is specific to floating-point numbers and treats NaN as missing data.

std::fmax/std::fmin

The contents and meaning of the header <cmath> are the same as the C standard library header <math.h> [...]

- C++23 standard : [cmath.syn] p1

If just one argument is a NaN, the fmax functions return the other argument (if both arguments are NaNs, the functions return a NaN).
[...]
The body of the fmax function might be

{ return (isgreaterequal(x, y) || isnan(y)) ? x : y; }

- C17 standard: F.10.9.2 The fmax functions

It's also worth noting that fmax/fmin may be sensitive to the sign of zero:

Ideally, fmax would be sensitive to the sign of zero, for example fmax(−0.0, +0.0) would return +0; however, implementation in software might be impractical.

- C17 standard: footnote 380

std::max/std::min

template<class T>
constexpr const T& max(const T& a, const T& b);
// [...]

Preconditions: For the first form, T meets the Cpp17LessThanComparable requirements (Table 29).

Returns: The larger value. Returns the first argument when the arguments are equivalent.

- [alg.min.max] std::max

There is no sample implementation in the standard, but a possible implementation looks like:

{ return a < b ? b : a; }

Which one to choose

For performance reasons, it is better to use std::max and std::min.
On modern x86_64, std::max compiles to a single instruction

vmaxss  xmm0, xmm1, xmm0            ; xmm0 = max(xmm1, xmm0)

... whereas std::fmax compiles to

vmaxss      xmm2, xmm1, xmm0        ; xmm2 = max(xmm1, xmm0)
vcmpunordss xmm0, xmm0, xmm0        ; test xmm0 for NaN, set mask bits
vblendvps   xmm0, xmm2, xmm1, xmm0  ; xmm0 = isnan(xmm0) ? xmm1 : xmm2

See Compiler Explorer.

If there's no possibility of operands being NaN, you should go for std::max/std::min. Otherwise, use std::fmax/std::fmin.

Further Notes on Assembly

std::fmax(x, y) cannot be implemented using only vmaxss dest, y, x because if x or y is NaN, dest = x. std::fmax chooses x or y depending on which one isn't NaN. vmaxss is biased towards x in every possible way.

However, vmaxss matches the behavior of x < y ? y : x and thus std::max exactly.

软糯酥胸 2024-08-15 21:50:45

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

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

min (10, BigExpensiveFunctionCall())

该函数调用可能会被调用两次,具体取决于宏的实现。因此,我的组织中的最佳实践是永远不要使用非文字或变量的内容调用 min 或 max 。

I always use the min and max macros for ints. I'm not sure why anyone would use fmin or fmax for integer values.

The big gotcha with min and max is that they're not functions, even if they look like them. If you do something like:

min (10, BigExpensiveFunctionCall())

That function call may get called twice depending on the implementation of the macro. As such, its best practice in my org to never call min or max with things that aren't a literal or variable.

月下客 2024-08-15 21:50:45

在比较有符号和无符号整数时,可以首选 fminlfmaxl 中的 fminfmax - 您可以利用事实上,有符号和无符号数字的整个范围,您不必担心整数范围和提升。

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

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

fmin and fmax, of fminl and fmaxl could be preferred when comparing signed and unsigned integers - you can take advantage of the fact that the entire range of signed and unsigned numbers and you don't have to worry about integer ranges and promotions.

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

int z = min(x, y);
z = (int)fmin(x, y);
新雨望断虹 2024-08-15 21:50:45

主要区别在于它们所操作的值的类型。 std::minstd::max 更通用,可以与各种数据类型一起使用,而 fminfmax< /code> 是专门为浮点数设计的。如果您使用整数或其他类型,则应使用 std::minstd::max

The key difference is in the types of values they operate on. std::min and std::max are more general and can be used with various data types, while fmin and fmax are specifically designed for floating-point numbers. If you are working with integers or other types, you should use std::min and std::max.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文