我想要一个函数为负数返回-1,为正数返回+1。 http://en.wikipedia.org/wiki/Sign_function 我自己编写它很容易,但它似乎应该存在于某个标准库中。
编辑:具体来说,我正在寻找一个函数工作在浮动。
我想要一个函数为负数返回-1,为正数返回+1。 http://en.wikipedia.org/wiki/Sign_function 我自己编写它很容易,但它似乎应该存在于某个标准库中。
编辑:具体来说,我正在寻找一个函数工作在浮动。
当前回答
类型安全的c++版本:
template <typename T> int sgn(T val) {
return (T(0) < val) - (val < T(0));
}
好处:
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.
警告:
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 signum is 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.)
其他回答
下面重载的接受答案确实不会触发-Wtype-limits。但它确实会触发未使用的参数警告(针对is_signed变量)。为了避免这些,第二个参数不应该这样命名:
template <typename T> inline constexpr
int signum(T x, std::false_type) {
return T(0) < x;
}
template <typename T> inline constexpr
int signum(T x, std::true_type) {
return (T(0) < x) - (x < T(0));
}
template <typename T> inline constexpr
int signum(T x) {
return signum(x, std::is_signed<T>());
}
对于c++ 11或更高版本,可以选择。
template <typename T>
typename std::enable_if<std::is_unsigned<T>::value, int>::type
inline constexpr signum(T const x) {
return T(0) < x;
}
template <typename T>
typename std::enable_if<std::is_signed<T>::value, int>::type
inline constexpr signum(T const x) {
return (T(0) < x) - (x < T(0));
}
对我来说,它不会触发GCC 5.3.1上的任何警告。
我不知道它的标准函数。这里有一种有趣的写法:
(x > 0) - (x < 0)
这里有一个更容易理解的方法:
if (x > 0) return 1;
if (x < 0) return -1;
return 0;
如果你喜欢三元运算符,你可以这样做:
(x > 0) ? 1 : ((x < 0) ? -1 : 0)
不,它在c++中不存在,就像在matlab中一样。我在程序中使用宏来实现这一点。
#define sign(a) ( ( (a) < 0 ) ? -1 : ( (a) > 0 ) )
虽然接受的答案中的整数解决方案相当优雅,但它不能为双类型返回NAN,因此我对它进行了稍微修改。
template <typename T> double sgn(T val) {
return double((T(0) < val) - (val < T(0)))/(val == val);
}
请注意,返回一个浮点NAN而不是硬编码NAN会导致在某些实现中设置符号位,因此val = -NAN和val = NAN的输出无论如何都是相同的(如果你更喜欢“NAN”输出而不是-NAN,你可以在返回之前放一个abs(val)…)
有一种不用分支的方法,但不太好。
sign = -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));
http://graphics.stanford.edu/~seander/bithacks.html
那一页上还有很多其他有趣的、过于聪明的东西……