C/C++ 中是否有标准的符号函数(signum、sgn)?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1903954/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 21:33:16  来源:igfitidea点击:

Is there a standard sign function (signum, sgn) in C/C++?

c++cmath

提问by batty

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

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

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

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

回答by

Surprised no one has posted the type-safe C++ version yet:

令人惊讶的是,还没有人发布类型安全的 C++ 版本:

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! copysignis 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.
  • 实际上实现了符号(-1、0 或 1)。此处使用 copysign 的实现仅返回 -1 或 1,这不是 signum。此外,这里的一些实现返回的是浮点数(或 T)而不是整数,这似乎很浪费。
  • 适用于整数、浮点数、双精度数、无符号短数或任何可从整数 0 构造且可排序的自定义类型。
  • 快速地!copysign很慢,特别是如果您需要提升然后再次缩小。这是无分支的并且优化得很好
  • 符合标准!bitshift hack 很简洁,但仅适用于某些位表示,并且在您拥有无符号类型时不起作用。在适当的时候,它可以作为手动专业化提供。
  • 准确的!与零的简单比较可以保持机器内部的高精度表示(例如 x87 上的 80 位),并避免过早舍入到零。

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 signumis more understandable.
  • The < 0part of the check triggers GCC's -Wtype-limitswarning 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.)

  • 它是一个模板,因此在某些情况下编译可能需要更长的时间。
  • 显然,有些人认为使用一个新的、有点深奥的、非常慢的标准库函数甚至没有真正实现 signum更容易理解。
  • < 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>());
    }
    

    (这是第一个警告的一个很好的例子。)

回答by Mark Byers

I don't know of a standard function for it. Here's an interesting way to write it though:

我不知道它的标准功能。不过,这是一种有趣的编写方式:

(x > 0) - (x < 0)

Here's a more readable way to do it:

这是一种更具可读性的方法:

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

If you like the ternary operator you can do this:

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

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

回答by comingstorm

There is a C99 math library function called copysign(), which takes the sign from one argument and the absolute value from the other:

有一个名为 copysign() 的 C99 数学库函数,它从一个参数中获取符号,从另一个参数中获取绝对值:

result = copysign(1.0, value) // double
result = copysignf(1.0, value) // float
result = copysignl(1.0, value) // long double

will give you a result of +/- 1.0, depending on the sign of value. Note that floating point zeroes are signed: (+0) will yield +1, and (-0) will yield -1.

根据值的符号,将为您提供 +/- 1.0 的结果。请注意,浮点零是有符号的:(+0) 将产生 +1,而 (-0) 将产生 -1。

回答by Catskul

It seems that most of the answers missed the original question.

似乎大多数答案都错过了原始问题。

Is there a standard sign function (signum, sgn) in C/C++?

C/C++ 中是否有标准的符号函数(signum、sgn)?

Not in the standard library, however there is copysignwhich can be used almost the same way via copysign(1.0, arg)and there is a true sign function in boost, which might as well be part of the standard.

不在标准库中,但是copysign可以通过几乎相同的方式使用它,copysign(1.0, arg)并且在 中有一个真正的符号函数boost,它也可能是标准的一部分。

    #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);

http://www.boost.org/doc/libs/1_47_0/libs/math/doc/sf_and_dist/html/math_toolkit/utils/sign_functions.html

http://www.boost.org/doc/libs/1_47_0/libs/math/doc/sf_and_dist/html/math_toolkit/utils/sign_functions.html

回答by John

Apparently, the answer to the original poster's question is no. There is no standardC++ sgnfunction.

显然,原始海报问题的答案是否定的。没有标准的C++sgn函数。

回答by chux - Reinstate Monica

Is there a standard sign function (signum, sgn) in C/C++?

C/C++ 中是否有标准的符号函数(signum、sgn)?

Yes, depending on definition.

是的,取决于定义。

C99 and later has the signbit()macro in <math.h>

C99 及更高版本的signbit()宏在<math.h>

int signbit(real-floating x);
The signbitmacro returns a nonzero value if and only if the sign of its argument value is negative. C11 §7.12.3.6

int signbit(真实浮动x);当且仅当其参数值的符号为负时
signbit宏才返回非零值。C11 §7.12.3.6



Yet OP wants something a little different.

然而 OP 想要一些不同的东西。

I want a function that returns -1 for negative numbers and +1 for positive numbers. ... a function working on floats.

我想要一个函数,它为负数返回 -1,为正数返回 +1。... 一个处理浮点数的函数。

#define signbit_p1_or_n1(x)  ((signbit(x) ?  -1 : 1)


Deeper:

更深层次的:

The post is not specific in the following cases: x = 0.0, -0.0, +NaN, -NaN.

在以下情况下,该帖子不具体:x = 0.0, -0.0, +NaN, -NaN.

A classic signum()returns +1on x>0, -1on x<0and 0on x==0.

一个经典的signum()回报+1x>0-1x<00x==0

Many answers have already covered that, but do not address x = -0.0, +NaN, -NaN. Many are geared for an integer point-of-view that usually lacks Not-a-Numbers (NaN) and -0.0.

许多答案已经涵盖了这一点,但没有解决x = -0.0, +NaN, -NaN。许多面向整数的观点,通常缺乏非数字(NaN)和-0.0

Typical answers function like signnum_typical()On -0.0, +NaN, -NaN, they return 0.0, 0.0, 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;
}

Instead, I propose this functionality: On -0.0, +NaN, -NaN, it returns -0.0, +NaN, -NaN.

相反,我提出了这个功能: 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;
}

回答by xnx

Faster than the above solutions, including the highest rated one:

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

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

回答by Tim Sylvester

There's a way to do it without branching, but it's not very pretty.

有一种方法可以在不分支的情况下做到这一点,但它不是很漂亮。

sign = -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));

http://graphics.stanford.edu/~seander/bithacks.html

http://graphics.stanford.edu/~seander/bithacks.html

Lots of other interesting, overly-clever stuff on that page, too...

该页面上还有许多其他有趣,过于聪明的东西......

回答by ysth

If all you want is to test the sign, use signbit(returns true if its argument has a negative sign). Not sure why you would particularly want -1 or +1 returned; copysign is more convenient for that, but it sounds like it will return +1 for negative zero on some platforms with only partial support for negative zero, where signbit presumably would return true.

如果您只想测试符号,请使用signbit(如果其参数具有负号,则返回 true)。不知道为什么您特别希望返回 -1 或 +1;copysign 对此更方便,但听起来它会在某些平台上为负零返回 +1,仅部分支持负零,其中 signbit 可能会返回 true。

回答by High Performance Mark

My copy of C in a Nutshell reveals the existence of a standard function called copysign which might be useful. It looks as if copysign(1.0, -2.0) would return -1.0 and copysign(1.0, 2.0) would return +1.0.

我在 Nutshell 中的 C 副本揭示了一个名为 copysign 的标准函数的存在,它可能很有用。看起来 copysign(1.0, -2.0) 会返回 -1.0 而 copysign(1.0, 2.0) 会返回 +1.0。

Pretty close huh?

很接近吧?