我想要一个函数为负数返回-1,为正数返回+1。 http://en.wikipedia.org/wiki/Sign_function 我自己编写它很容易,但它似乎应该存在于某个标准库中。
编辑:具体来说,我正在寻找一个函数工作在浮动。
我想要一个函数为负数返回-1,为正数返回+1。 http://en.wikipedia.org/wiki/Sign_function 我自己编写它很容易,但它似乎应该存在于某个标准库中。
编辑:具体来说,我正在寻找一个函数工作在浮动。
当前回答
如果boost可用,可以使用boost/math/special_functions/sign.hpp中的boost::math::sign()方法。
其他回答
不,它在c++中不存在,就像在matlab中一样。我在程序中使用宏来实现这一点。
#define sign(a) ( ( (a) < 0 ) ? -1 : ( (a) > 0 ) )
比上述解决方案更快,包括评级最高的一个:
(x < 0) ? -1 : (x > 0)
这是一个分支友好的实现:
inline int signum(const double x) {
if(x == 0) return 0;
return (1 - (static_cast<int>((*reinterpret_cast<const uint64_t*>(&x)) >> 63) << 1));
}
除非你的数据有一半是0,否则分支预测器会选择一个最常见的分支。两个分支都只涉及简单的操作。
另外,在一些编译器和CPU架构上,完全无分支的版本可能更快:
inline int signum(const double x) {
return (x != 0) *
(1 - (static_cast<int>((*reinterpret_cast<const uint64_t*>(&x)) >> 63) << 1));
}
这适用于IEEE 754双精度二进制浮点格式:binary64。
为什么使用三元操作符和if-else,当你可以简单地这样做
#define sgn(x) x==0 ? 0 : x/abs(x)
下面重载的接受答案确实不会触发-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上的任何警告。