我想要一个函数,对于负数返回-1,对于正数返回+1. http://en.wikipedia.org/wiki/Sign_function 写我自己很容易,但似乎应该在某个标准库中.
编辑:具体来说,我正在寻找一个工作浮动的功能.
小智 486
惊讶没有人发布无分支,类型安全的C++版本:
template <typename T> int sgn(T val) {
return (T(0) < val) - (val < T(0));
}
Run Code Online (Sandbox Code Playgroud)
优点:
copysign很慢,特别是如果你需要提升然后再缩小.这是无分支的,并且优化得非常好注意事项:
在为无符号类型实例化时< 0,检查的部分会触发GCC的-Wtype-limits警告.您可以通过使用一些重载来避免这种情况:
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>());
}
Run Code Online (Sandbox Code Playgroud)
(这是第一个警告的一个很好的例子.)
Mar*_*ers 266
我不知道它的标准功能.这是一个有趣的写作方式:
(x > 0) - (x < 0)
Run Code Online (Sandbox Code Playgroud)
这是一种更易读的方法:
if (x > 0) return 1;
if (x < 0) return -1;
return 0;
Run Code Online (Sandbox Code Playgroud)
如果你喜欢三元运算符,你可以这样做:
(x > 0) ? 1 : ((x < 0) ? -1 : 0)
Run Code Online (Sandbox Code Playgroud)
com*_*orm 186
有一个名为copysign()的C99数学库函数,它从一个参数获取符号,从另一个参数获取绝对值:
result = copysign(1.0, value) // double
result = copysignf(1.0, value) // float
result = copysignl(1.0, value) // long double
Run Code Online (Sandbox Code Playgroud)
会给你+/- 1.0的结果,具体取决于价值的符号.请注意,浮点零是有符号的:(+ 0)将产生+1,而( - 0)将产生-1.
Cat*_*kul 76
似乎大部分答案都错过了原来的问题.
C/C++中是否有标准符号函数(signum,sgn)?
不在标准库中,但存在copysign,也可能是标准的一部分.
#include <boost/math/special_functions/sign.hpp>
//Returns 1 if x > 0, -1 if x < 0, and 0 if x is zero.
template <class T>
inline int sign (const T& z);
Run Code Online (Sandbox Code Playgroud)
Joh*_*ohn 74
显然,原始海报问题的答案是否定的.没有标准的 C++ sgn函数.
xnx*_*xnx 29
比上述解决方案更快,包括评分最高的解决方案:
(x < 0) ? -1 : (x > 0)
Run Code Online (Sandbox Code Playgroud)
chu*_*ica 25
C/C++中是否有标准符号函数(signum,sgn)?
是的,取决于定义.
C99及更高版本中有signbit()宏<math.h>
int signbit(实际浮动x); 当且仅当其参数值的符号为负时
,signbit宏才返回非零值.C11§7.12.3.6
OP想要一些不同的东西.
我想要一个函数,对于负数返回-1,对于正数返回+1....一个处理花车的功能.
#define signbit_p1_or_n1(x) ((signbit(x) ? -1 : 1)
Run Code Online (Sandbox Code Playgroud)
更深的:
该帖子在以下情况下并不具体,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;
}
Run Code Online (Sandbox Code Playgroud)
相反,建议使用此功能: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;
}
Run Code Online (Sandbox Code Playgroud)
Tim*_*ter 17
有一种方法可以不分支,但它不是很漂亮.
sign = -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));
Run Code Online (Sandbox Code Playgroud)
http://graphics.stanford.edu/~seander/bithacks.html
该页面上还有很多其他有趣,过于聪明的东西......
我在坚果壳中的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个符号,即使是零值.
| 归档时间: |
|
| 查看次数: |
335312 次 |
| 最近记录: |