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

C++CMath

C++ Problem Overview


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.

C++ Solutions


Solution 1 - C++

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.)

Solution 2 - C++

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)

Solution 3 - C++

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

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.

Solution 4 - C++

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

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

Not in the standard library, however there is copysign which 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.

    #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

Solution 5 - C++

Apparently, the answer to the original poster's question is no. There is no standard C++ sgn function.

Solution 6 - C++

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

Yes, depending on definition.

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

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


Yet OP wants something a little different.

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

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

Deeper:

OP's question is not specific in the following cases: x = 0.0, -0.0, +NaN, -NaN.

A classic signum() returns +1 on x>0, -1 on x<0 and 0 on x==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.

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

double signnum_c(double x) {
  if (x > 0.0) return 1.0;
  if (x < 0.0) return -1.0;
  return x;
}

Solution 7 - C++

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

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

Solution 8 - C++

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

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

Solution 9 - C++

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.

Solution 10 - C++

In general, there is no standard signum function in C/C++, and the lack of such a fundamental function tells you a lot about these languages.

Apart from that, I believe both majority viewpoints about the right approach to define such a function are in a way correct, and the "controversy" about it is actually a non-argument once you take into account two important caveats:

  • A signum function should always return the type of its operand, similarly to an abs() function, because signum is usually used for multiplication with an absolute value after the latter has been processed somehow. Therefore, the major use case of signum is not comparisons but arithmetic, and the latter shouldn't involve any expensive integer-to/from-floating-point conversions.

  • Floating point types do not feature a single exact zero value: +0.0 can be interpreted as "infinitesimally above zero", and -0.0 as "infinitesimally below zero". That's the reason why comparisons involving zero must internally check against both values, and an expression like x == 0.0 can be dangerous.

Regarding C, I think the best way forward with integral types is indeed to use the (x > 0) - (x < 0) expression, as it should be translated in a branch-free fashion, and requires only three basic operations. Best define inline functions that enforce a return type matching the argument type, and add a C11 define _Generic to map these functions to a common name.

With floating point values, I think inline functions based on C11 copysignf(1.0f, x), copysign(1.0, x), and copysignl(1.0l, x) are the way to go, simply because they're also highly likely to be branch-free, and additionally do not require casting the result from integer back into a floating point value. You should probably comment prominently that your floating point implementations of signum will not return zero because of the peculiarities of floating point zero values, processing time considerations, and also because it is often very useful in floating point arithmetic to receive the correct -1/+1 sign, even for zero values.

Solution 11 - C++

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.

Pretty close huh?

Solution 12 - C++

The accepted answer with the overload below does indeed not trigger -Wtype-limits. But it does trigger unused argument warnings (on the is_signed variable). To avoid these the second argument should not be named like so:

template <typename T> inline constexpr
  int signum(T x, std::false_type) {
  return T(0) < x;
}

template <typename T> inline constexpr
  int signum(T x, std::true_type) {
  return (T(0) < x) - (x < T(0));
}

template <typename T> inline constexpr
  int signum(T x) {
  return signum(x, std::is_signed<T>());
}

For C++11 and higher an alternative could be.

template <typename T>
typename std::enable_if<std::is_unsigned<T>::value, int>::type
inline constexpr signum(T const x) {
    return T(0) < x;  
}

template <typename T>
typename std::enable_if<std::is_signed<T>::value, int>::type
inline constexpr signum(T const x) {
    return (T(0) < x) - (x < T(0));  
}

For me it does not trigger any warnings on GCC 5.3.1.

Solution 13 - C++

No, it doesn't exist in c++, like in matlab. I use a macro in my programs for this.

#define sign(a) ( ( (a) < 0 )  ?  -1   : ( (a) > 0 ) )

Solution 14 - C++

The question is old but there is now this kind of desired function. I added a wrapper with not, left shift and dec.

You can use a wrapper function based on signbit from C99 in order to get the exact desired behavior (see code further below).

> Returns whether the sign of x is negative.
This can be also applied to infinites, NaNs and zeroes (if zero is unsigned, it is considered positive

#include <math.h>

int signValue(float a) {
    return ((!signbit(a)) << 1) - 1;
}

NB: I use operand not ("!") because the return value of signbit is not specified to be 1 (even though the examples let us think it would always be this way) but true for a negative number:

> Return value
A non-zero value (true) if the sign of x is negative; and zero (false) otherwise.

Then I multiply by two with left shift (" << 1") which will give us 2 for a positive number and 0 for a negative one and finally decrement by 1 to obtain 1 and -1 for respectively positive and negative numbers as requested by OP.

Solution 15 - C++

Bit off-topic, but I use this:

template<typename T>
constexpr int sgn(const T &a, const T &b) noexcept{
	return (a > b) - (a < b);
}

template<typename T>
constexpr int sgn(const T &a) noexcept{
	return sgn(a, T(0));
}

and I found first function - the one with two arguments, to be much more useful from "standard" sgn(), because it is most often used in code like this:

int comp(unsigned a, unsigned b){
   return sgn( int(a) - int(b) );
}

vs.

int comp(unsigned a, unsigned b){
   return sgn(a, b);
}

there is no cast for unsigned types and no additional minus.

in fact i have this piece of code using sgn()

template <class T>
int comp(const T &a, const T &b){
	log__("all");
	if (a < b)
		return -1;

	if (a > b)
		return +1;

	return 0;
}

inline int comp(int const a, int const b){
	log__("int");
	return a - b;
}

inline int comp(long int const a, long int const b){
	log__("long");
	return sgn(a, b);
}

Solution 16 - C++

You can use boost::math::sign() method from boost/math/special_functions/sign.hpp if boost is available.

Solution 17 - C++

While the integer solution in the accepted answer is quite elegant it bothered me that it wouldn't be able to return NAN for double types, so I modified it slightly.

template <typename T> double sgn(T val) {
    return double((T(0) < val) - (val < T(0)))/(val == val);
}

Note that returning a floating point NAN as opposed to a hard coded NAN causes the sign bit to be set in some implementations, so the output for val = -NAN and val = NAN are going to be identical no matter what (if you prefer a "nan" output over a -nan you can put an abs(val) before the return...)

Solution 18 - C++

Here's a branching-friendly implementation:

inline int signum(const double x) {
    if(x == 0) return 0;
    return (1 - (static_cast<int>((*reinterpret_cast<const uint64_t*>(&x)) >> 63) << 1));
}

Unless your data has zeros as half of the numbers, here the branch predictor will choose one of the branches as the most common. Both branches only involve simple operations.

Alternatively, on some compilers and CPU architectures a completely branchless version may be faster:

inline int signum(const double x) {
    return (x != 0) * 
        (1 - (static_cast<int>((*reinterpret_cast<const uint64_t*>(&x)) >> 63) << 1));
}

This works for IEEE 754 double-precision binary floating-point format: binary64 .

Solution 19 - C++

int sign(float n)
{     
  union { float f; std::uint32_t i; } u { n };
  return 1 - ((u.i >> 31) << 1);
}

This function assumes:

  • binary32 representation of floating point numbers
  • a compiler that make an exception about the strict aliasing rule when using a named union

Solution 20 - C++

double signof(double a) { return (a == 0) ? 0 : (a<0 ? -1 : 1); }

Solution 21 - C++

Why use ternary operators and if-else when you can simply do this

#define sgn(x) x==0 ? 0 : x/abs(x)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionbattyView Question on Stackoverflow
Solution 1 - C++user79758View Answer on Stackoverflow
Solution 2 - C++Mark ByersView Answer on Stackoverflow
Solution 3 - C++comingstormView Answer on Stackoverflow
Solution 4 - C++CatskulView Answer on Stackoverflow
Solution 5 - C++JohnView Answer on Stackoverflow
Solution 6 - C++chux - Reinstate MonicaView Answer on Stackoverflow
Solution 7 - C++xnxView Answer on Stackoverflow
Solution 8 - C++Tim SylvesterView Answer on Stackoverflow
Solution 9 - C++ysthView Answer on Stackoverflow
Solution 10 - C++TabernakelView Answer on Stackoverflow
Solution 11 - C++High Performance MarkView Answer on Stackoverflow
Solution 12 - C++SamVanDonutView Answer on Stackoverflow
Solution 13 - C++chatteringView Answer on Stackoverflow
Solution 14 - C++Antonin GAVRELView Answer on Stackoverflow
Solution 15 - C++NickView Answer on Stackoverflow
Solution 16 - C++khkarensView Answer on Stackoverflow
Solution 17 - C++mrclngView Answer on Stackoverflow
Solution 18 - C++Serge RogatchView Answer on Stackoverflow
Solution 19 - C++GigiView Answer on Stackoverflow
Solution 20 - C++cyberionView Answer on Stackoverflow
Solution 21 - C++JagreetView Answer on Stackoverflow