我想要一个函数为负数返回-1,为正数返回+1。 http://en.wikipedia.org/wiki/Sign_function 我自己编写它很容易,但它似乎应该存在于某个标准库中。

编辑:具体来说,我正在寻找一个函数工作在浮动。


当前回答

有点跑题了,但我用了这个:

template<typename T>
constexpr int sgn(const T &a, const T &b) noexcept{
    return (a > b) - (a < b);
}

template<typename T>
constexpr int sgn(const T &a) noexcept{
    return sgn(a, T(0));
}

我发现第一个函数-有两个参数的函数,比“标准”sgn()更有用,因为它最常在这样的代码中使用:

int comp(unsigned a, unsigned b){
   return sgn( int(a) - int(b) );
}

vs.

int comp(unsigned a, unsigned b){
   return sgn(a, b);
}

无符号类型没有强制转换,也没有额外的减号。

这段代码是用sgn()写的

template <class T>
int comp(const T &a, const T &b){
    log__("all");
    if (a < b)
        return -1;

    if (a > b)
        return +1;

    return 0;
}

inline int comp(int const a, int const b){
    log__("int");
    return a - b;
}

inline int comp(long int const a, long int const b){
    log__("long");
    return sgn(a, b);
}

其他回答

比上述解决方案更快,包括评级最高的一个:

(x < 0) ? -1 : (x > 0)

我不知道它的标准函数。这里有一种有趣的写法:

(x > 0) - (x < 0)

这里有一个更容易理解的方法:

if (x > 0) return 1;
if (x < 0) return -1;
return 0;

如果你喜欢三元运算符,你可以这样做:

(x > 0) ? 1 : ((x < 0) ? -1 : 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。

double signof(double a) { return (a == 0) ? 0 : (a<0 ? -1 : 1); }
int sign(float n)
{     
  union { float f; std::uint32_t i; } u { n };
  return 1 - ((u.i >> 31) << 1);
}

这个函数假设:

浮点数的二进制32表示 在使用命名联合时对严格的混叠规则做出例外的编译器