我想要一个函数,对于负数返回-1,对于正数返回+1. http://en.wikipedia.org/wiki/Sign_function 写我自己很容易,但似乎应该在某个标准库中.
编辑:具体来说,我正在寻找一个工作浮动的功能.
惊讶没有人发布无分支,类型安全的C++版本:
templateint sgn(T val) { return (T(0) < val) - (val < T(0)); }
优点:
实际上实现signum(-1,0或1).这里使用copysign的实现只返回-1或1,这不是signum.此外,这里的一些实现返回float(或T)而不是int,这看起来很浪费.
适用于整数0和可订购的整数,浮动,双精度,无符号短裤或任何自定义类型.
快速!copysign
很慢,特别是如果你需要提升然后再缩小.这是无分支的,并且优化得非常好
符合标准的!bitshift hack很整洁,但只适用于某些位表示,并且当你有一个无符号类型时不起作用.它可以在适当时作为手动专业化提供.
准确!与零进行简单比较可以保持机器的内部高精度表示(例如x87上的80位),并避免过早的舍入到零.
注意事项:
这是一个模板,因此编译需要永远.
显然有些人认为使用一种新的,有点深奥且非常慢的标准库函数甚至不能真正实现signum更容易理解.
在为无符号类型实例化时< 0
,检查的部分会触发GCC的-Wtype-limits
警告.您可以通过使用一些重载来避免这种情况:
templateinline constexpr int signum(T x, std::false_type is_signed) { return T(0) < x; } template inline constexpr int signum(T x, std::true_type is_signed) { return (T(0) < x) - (x < T(0)); } template inline constexpr int signum(T x) { return signum(x, std::is_signed ()); }
(这是第一个警告的一个很好的例子.)
我不知道它的标准功能.这是一个有趣的写作方式:
(x > 0) - (x < 0)
这是一种更易读的方法:
if (x > 0) return 1; if (x < 0) return -1; return 0;
如果你喜欢三元运算符,你可以这样做:
(x > 0) ? 1 : ((x < 0) ? -1 : 0)
有一个名为copysign()的C99数学库函数,它从一个参数获取符号,从另一个参数获取绝对值:
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.
似乎大部分答案都错过了原来的问题.
C/C++中是否有标准符号函数(signum,sgn)?
不在标准库中,但存在copysign
,也可能是标准的一部分.
#include//Returns 1 if x > 0, -1 if x < 0, and 0 if x is zero. template inline int sign (const T& z);
http://www.boost.org/doc/libs/1_47_0/libs/math/doc/sf_and_dist/html/math_toolkit/utils/sign_functions.html
显然,原始海报问题的答案是否定的.没有标准的 C++ sgn
函数.
比上述解决方案更快,包括评分最高的解决方案:
(x < 0) ? -1 : (x > 0)
C/C++中是否有标准符号函数(signum,sgn)?
是的,取决于定义.
C99及更高版本中有signbit()
宏
int signbit
(实际浮动x
); 当且仅当其参数值的符号为负时
,signbit
宏才返回非零值.C11§7.12.3.6
OP想要一些不同的东西.
我想要一个函数,对于负数返回-1,对于正数返回+1....一个处理花车的功能.
#define signbit_p1_or_n1(x) ((signbit(x) ? -1 : 1)
更深的:
该帖子在以下情况下并不具体,x = 0.0, -0.0, +NaN, -NaN
.
一个经典的signum()
回报+1
上x>0
,-1
在x>0
与0
上x==0
.
许多答案已经涵盖了这一点,但没有解决x = -0.0, +NaN, -NaN
.许多都适用于通常缺少非数字(NaN)和-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; }
相反,建议使用此功能: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; }
有一种方法可以不分支,但它不是很漂亮.
sign = -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));
http://graphics.stanford.edu/~seander/bithacks.html
该页面上还有很多其他有趣,过于聪明的东西......
如果您只想测试符号,请使用signbit(如果其参数有负号,则返回true).不确定为什么你特别希望返回-1或+1; copysign更方便,但听起来它会在某些平台上为负零返回+1,只有部分支持负零,其中signbit可能会返回true.
我在坚果壳中的C副本揭示了一个叫做copysign的标准函数的存在,该函数可能会有用。看来copysign(1.0,-2.0)将返回-1.0,而copysign(1.0,2.0)将返回+1.0。
差不多吧?
一般来说,C/C++中没有标准的signum函数,缺乏这样的基本函数会告诉你很多这些语言.
除此之外,我认为关于定义这样一个函数的正确方法的多数观点在某种程度上是正确的,一旦你考虑到两个重要的警告,关于它的"争议"实际上是一个非争论:
甲正负号函数应该总是返回其操作数的类型,一个类似abs()
功能,因为正负号通常用于乘法与后者已经以某种方式处理后的绝对值.因此,signum的主要用例不是比较而是算术,后者不应涉及任何昂贵的整数到/从浮点转换.
浮点类型不具有单个精确零值:+0.0可以被解释为"无穷小地高于零",而-0.0被解释为"无穷小地低于零".这就是为什么涉及零的比较必须在内部检查这两个值,并且类似的表达式x == 0.0
可能是危险的.
关于C,我认为使用整数类型的最佳方法确实是使用(x > 0) - (x < 0)
表达式,因为它应该以无分支的方式进行转换,并且只需要三个基本操作.最佳定义内联函数,强制执行与参数类型匹配的返回类型,并添加C11 define _Generic
以将这些函数映射到公用名.
随着浮点值,我觉得基于C11内联函数copysignf(1.0f, x)
,copysign(1.0, x)
和copysignl(1.0l, x)
是要走的路,只是因为他们也极有可能成为分支免费的,另外也不需要从整回来铸造结果为浮点值.您应该突出地评论您的signum的浮点实现不会返回零,因为浮点零值的特殊性,处理时间考虑因素,并且因为它在浮点运算中通常非常有用以接收正确的-1/+ 1个符号,即使是零值.