C/C++ 中是否有标准的符号函数(signum、sgn)?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1903954/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there a standard sign function (signum, sgn) in C/C++?
提问by batty
I want a function that returns -1 for negative numbers and +1 for positive numbers. http://en.wikipedia.org/wiki/Sign_functionIt's easy enough to write my own, but it seems like something that ought to be in a standard library somewhere.
我想要一个函数,它为负数返回 -1,为正数返回 +1。 http://en.wikipedia.org/wiki/Sign_function编写我自己的很容易,但它似乎应该在某个标准库中的某个地方。
Edit: Specifically, I was looking for a function working on floats.
编辑:具体来说,我正在寻找一个处理浮动的函数。
回答by
Surprised no one has posted the type-safe C++ version yet:
令人惊讶的是,还没有人发布类型安全的 C++ 版本:
template <typename T> int sgn(T val) {
return (T(0) < val) - (val < T(0));
}
Benefits:
好处:
- Actually implements signum (-1, 0, or 1). Implementations here using copysign only return -1 or 1, which is not signum. Also, some implementations here are returning a float (or T) rather than an int, which seems wasteful.
- Works for ints, floats, doubles, unsigned shorts, or any custom types constructible from integer 0 and orderable.
- Fast!
copysign
is slow, especially if you need to promote and then narrow again. This is branchless and optimizes excellently - Standards-compliant! The bitshift hack is neat, but only works for some bit representations, and doesn't work when you have an unsigned type. It could be provided as a manual specialization when appropriate.
- Accurate! Simple comparisons with zero can maintain the machine's internal high-precision representation (e.g. 80 bit on x87), and avoid a premature round to zero.
- 实际上实现了符号(-1、0 或 1)。此处使用 copysign 的实现仅返回 -1 或 1,这不是 signum。此外,这里的一些实现返回的是浮点数(或 T)而不是整数,这似乎很浪费。
- 适用于整数、浮点数、双精度数、无符号短数或任何可从整数 0 构造且可排序的自定义类型。
- 快速地!
copysign
很慢,特别是如果您需要提升然后再次缩小。这是无分支的并且优化得很好 - 符合标准!bitshift hack 很简洁,但仅适用于某些位表示,并且在您拥有无符号类型时不起作用。在适当的时候,它可以作为手动专业化提供。
- 准确的!与零的简单比较可以保持机器内部的高精度表示(例如 x87 上的 80 位),并避免过早舍入到零。
Caveats:
注意事项:
- It's a template so it might take longer to compile in some circumstances.
- Apparently some people think use of a new, somewhat esoteric, and very slow standard library function that doesn't even really implement signumis more understandable.
The
< 0
part of the check triggers GCC's-Wtype-limits
warning when instantiated for an unsigned type. You can avoid this by using some overloads:template <typename T> inline constexpr int signum(T x, std::false_type is_signed) { return T(0) < x; } template <typename T> inline constexpr int signum(T x, std::true_type is_signed) { return (T(0) < x) - (x < T(0)); } template <typename T> inline constexpr int signum(T x) { return signum(x, std::is_signed<T>()); }
(Which is a good example of the first caveat.)
- 它是一个模板,因此在某些情况下编译可能需要更长的时间。
- 显然,有些人认为使用一个新的、有点深奥的、非常慢的标准库函数甚至没有真正实现 signum更容易理解。
该
< 0
检查的一部分触发GCC的-Wtype-limits
实例化一个无符号类型时警告。您可以通过使用一些重载来避免这种情况:template <typename T> inline constexpr int signum(T x, std::false_type is_signed) { return T(0) < x; } template <typename T> inline constexpr int signum(T x, std::true_type is_signed) { return (T(0) < x) - (x < T(0)); } template <typename T> inline constexpr int signum(T x) { return signum(x, std::is_signed<T>()); }
(这是第一个警告的一个很好的例子。)
回答by Mark Byers
I don't know of a standard function for it. Here's an interesting way to write it though:
我不知道它的标准功能。不过,这是一种有趣的编写方式:
(x > 0) - (x < 0)
Here's a more readable way to do it:
这是一种更具可读性的方法:
if (x > 0) return 1;
if (x < 0) return -1;
return 0;
If you like the ternary operator you can do this:
如果你喜欢三元运算符,你可以这样做:
(x > 0) ? 1 : ((x < 0) ? -1 : 0)
回答by comingstorm
There is a C99 math library function called copysign(), which takes the sign from one argument and the absolute value from the other:
有一个名为 copysign() 的 C99 数学库函数,它从一个参数中获取符号,从另一个参数中获取绝对值:
result = copysign(1.0, value) // double
result = copysignf(1.0, value) // float
result = copysignl(1.0, value) // long double
will give you a result of +/- 1.0, depending on the sign of value. Note that floating point zeroes are signed: (+0) will yield +1, and (-0) will yield -1.
根据值的符号,将为您提供 +/- 1.0 的结果。请注意,浮点零是有符号的:(+0) 将产生 +1,而 (-0) 将产生 -1。
回答by Catskul
It seems that most of the answers missed the original question.
似乎大多数答案都错过了原始问题。
Is there a standard sign function (signum, sgn) in C/C++?
C/C++ 中是否有标准的符号函数(signum、sgn)?
Not in the standard library, however there is copysign
which can be used almost the same way via copysign(1.0, arg)
and there is a true sign function in boost
, which might as well be part of the standard.
不在标准库中,但是copysign
可以通过几乎相同的方式使用它,copysign(1.0, arg)
并且在 中有一个真正的符号函数boost
,它也可能是标准的一部分。
#include <boost/math/special_functions/sign.hpp>
//Returns 1 if x > 0, -1 if x < 0, and 0 if x is zero.
template <class T>
inline int sign (const T& z);
回答by John
Apparently, the answer to the original poster's question is no. There is no standardC++ sgn
function.
显然,原始海报问题的答案是否定的。没有标准的C++sgn
函数。
回答by chux - Reinstate Monica
Is there a standard sign function (signum, sgn) in C/C++?
C/C++ 中是否有标准的符号函数(signum、sgn)?
Yes, depending on definition.
是的,取决于定义。
C99 and later has the signbit()
macro in <math.h>
C99 及更高版本的signbit()
宏在<math.h>
int signbit
(real-floatingx
);
Thesignbit
macro returns a nonzero value if and only if the sign of its argument value is negative. C11 §7.12.3.6
int signbit
(真实浮动x
);当且仅当其参数值的符号为负时
,signbit
宏才返回非零值。C11 §7.12.3.6
Yet OP wants something a little different.
然而 OP 想要一些不同的东西。
I want a function that returns -1 for negative numbers and +1 for positive numbers. ... a function working on floats.
我想要一个函数,它为负数返回 -1,为正数返回 +1。... 一个处理浮点数的函数。
#define signbit_p1_or_n1(x) ((signbit(x) ? -1 : 1)
Deeper:
更深层次的:
The post is not specific in the following cases: x = 0.0, -0.0, +NaN, -NaN
.
在以下情况下,该帖子不具体:x = 0.0, -0.0, +NaN, -NaN
.
A classic signum()
returns +1
on x>0
, -1
on x<0
and 0
on x==0
.
一个经典的signum()
回报+1
上x>0
,-1
在x<0
与0
上x==0
。
Many answers have already covered that, but do not address x = -0.0, +NaN, -NaN
. Many are geared for an integer point-of-view that usually lacks Not-a-Numbers (NaN) and -0.0.
许多答案已经涵盖了这一点,但没有解决x = -0.0, +NaN, -NaN
。许多面向整数的观点,通常缺乏非数字(NaN)和-0.0。
Typical answers function like signnum_typical()
On -0.0, +NaN, -NaN
, they return 0.0, 0.0, 0.0
.
典型的答案功能类似于signnum_typical()
On -0.0, +NaN, -NaN
,它们返回0.0, 0.0, 0.0
。
int signnum_typical(double x) {
if (x > 0.0) return 1;
if (x < 0.0) return -1;
return 0;
}
Instead, I propose this functionality: On -0.0, +NaN, -NaN
, it returns -0.0, +NaN, -NaN
.
相反,我提出了这个功能: On -0.0, +NaN, -NaN
,它返回-0.0, +NaN, -NaN
。
double signnum_c(double x) {
if (x > 0.0) return 1.0;
if (x < 0.0) return -1.0;
return x;
}
回答by xnx
Faster than the above solutions, including the highest rated one:
比上述解决方案更快,包括评分最高的解决方案:
(x < 0) ? -1 : (x > 0)
回答by Tim Sylvester
There's a way to do it without branching, but it's not very pretty.
有一种方法可以在不分支的情况下做到这一点,但它不是很漂亮。
sign = -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));
http://graphics.stanford.edu/~seander/bithacks.html
http://graphics.stanford.edu/~seander/bithacks.html
Lots of other interesting, overly-clever stuff on that page, too...
该页面上还有许多其他有趣,过于聪明的东西......
回答by ysth
If all you want is to test the sign, use signbit(returns true if its argument has a negative sign). Not sure why you would particularly want -1 or +1 returned; copysign is more convenient for that, but it sounds like it will return +1 for negative zero on some platforms with only partial support for negative zero, where signbit presumably would return true.
如果您只想测试符号,请使用signbit(如果其参数具有负号,则返回 true)。不知道为什么您特别希望返回 -1 或 +1;copysign 对此更方便,但听起来它会在某些平台上为负零返回 +1,仅部分支持负零,其中 signbit 可能会返回 true。
回答by High Performance Mark
My copy of C in a Nutshell reveals the existence of a standard function called copysign which might be useful. It looks as if copysign(1.0, -2.0) would return -1.0 and copysign(1.0, 2.0) would return +1.0.
我在 Nutshell 中的 C 副本揭示了一个名为 copysign 的标准函数的存在,它可能很有用。看起来 copysign(1.0, -2.0) 会返回 -1.0 而 copysign(1.0, 2.0) 会返回 +1.0。
Pretty close huh?
很接近吧?