I want a function that returns -1 for negative numbers and +1 for positive numbers. http://en.wikipedia.org/wiki/Sign_function It's easy enough to write my own, but it seems like something that ought to be in a standard library somewhere.

Edit: Specifically, I was looking for a function working on floats.

推荐答案

The type-safe C++ version:

template <typename T> int sgn(T val) {
    return (T(0) < val) - (val < T(0));
}

Benefits:

  • Actually implements signum (-1, 0, or 1). Implementations here using copysign only return -1 or 1, which is not signum. Also, some implementations here are returning a float (or T) rather than an int, which seems wasteful.
  • Works for ints, floats, doubles, unsigned shorts, or any custom types constructible from integer 0 and orderable.
  • Fast! copysign is slow, especially if you need to promote and then narrow again. This is branchless and optimizes excellently
  • Standards-compliant! The bitshift hack is neat, but only works for some bit representations, and doesn't work when you have an unsigned type. It could be provided as a manual specialization when appropriate.
  • Accurate! Simple comparisons with zero can maintain the machine's internal high-precision representation (e.g. 80 bit on x87), and avoid a premature round to zero.

Caveats:

  • It's a template so it might take longer to compile in some circumstances.

  • Apparently some people think use of a new, somewhat esoteric, and very slow standard library function that doesn't even really implement signum is more understandable.

  • The < 0 part of the check triggers GCC's -Wtype-limits warning when instantiated for an unsigned type. You can avoid this by using some overloads:

     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>());
     }
    

    (Which is a good example of the first caveat.)

C++相关问答推荐

为什么GCC在每次循环迭代时都会生成一个数组的mov&S使用[]访问数组?(-03,x86)

如何在C中通过套接字自定义数据类型读取原始变量?

为什么我一直收到分段错误?

如何计算打印二叉搜索树时每行所需的空间?

C指针概念分段故障

如何使用唯一数字对整型进行分区

在C++中允许使用字符作为宏参数

将数组插入数组

使用ld将目标文件链接到C标准库

使用Open62541向OPCUA服务器发送读请求时内存泄漏

使用C++中的字符串初始化 struct 时,从‘char*’初始化‘char’使指针变为整数,而不进行强制转换

*S=0;正在优化中.可能是GCC 13号虫?或者是一些不明确的行为?

将某些内容添加到链接列表时,列表中的其他项将使用最后添加的项的名称

当我将偏移量更改为任何非零值时,C中的mmap共享内存出现无效参数错误

挥发性语义的形式化理解

通过char*访问指针的对象表示是未定义的行为吗?

STM32:代码的执行似乎取决于它在闪存中的位置

为什么 C 字符串并不总是等同于字符数组?

C 初学者 - struct 中的字符串不需要 Malloc

牛顿分形优化