我想要一个函数为负数返回-1,为正数返回+1。 http://en.wikipedia.org/wiki/Sign_function 我自己编写它很容易,但它似乎应该存在于某个标准库中。
编辑:具体来说,我正在寻找一个函数工作在浮动。
我想要一个函数为负数返回-1,为正数返回+1。 http://en.wikipedia.org/wiki/Sign_function 我自己编写它很容易,但它似乎应该存在于某个标准库中。
编辑:具体来说,我正在寻找一个函数工作在浮动。
当前回答
有一个C99数学库函数叫copysign(),它从一个参数取符号,从另一个参数取绝对值:
result = copysign(1.0, value) // double
result = copysignf(1.0, value) // float
result = copysignl(1.0, value) // long double
会给你一个+/- 1.0的结果,这取决于值的符号。注意,浮点零是有符号的:(+0)将产生+1,(-0)将产生-1。
其他回答
int sign(float n)
{
union { float f; std::uint32_t i; } u { n };
return 1 - ((u.i >> 31) << 1);
}
这个函数假设:
浮点数的二进制32表示 在使用命名联合时对严格的混叠规则做出例外的编译器
这是一个分支友好的实现:
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); }
虽然接受的答案中的整数解决方案相当优雅,但它不能为双类型返回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)…)
为什么使用三元操作符和if-else,当你可以简单地这样做
#define sgn(x) x==0 ? 0 : x/abs(x)