tags:

views:

3703

answers:

8

I want a function that returns -1 for negative numbers and +1 for positive numbers. http://en.wikipedia.org/wiki/Sign%5Ffunction 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.

+37  A: 

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)
Mark Byers
Also one that works without branches. Nice.
Joey
My hat's off to you -- very nice.
Jerry Coffin
Would be interesting to time it against x<0?-1:1 and 1-2*(x<0).
Mark Ransom
Mark Ransom, your expressions give incorrect results for `x==0`.
avakar
I would nominate that for the monthly *style award* badge if there was any.
Georg Fritzsche
Compilers will generally optimize simple `?:` expressions into non-branching machine code.
Tim Sylvester
Sweet. How about `(x >= 0) - (x <= 0)'? Gives -1 for negative, 1 for positive, 0 for 0.
Fred Larson
I added some more "normal" methods too, before people complain that it's unreadable. ;-)
Mark Byers
Another ternary is `x ? (x < 0) ? -1 : 1 : 0`
caf
Is a true statement guaranteed to be exactly `1` in C?
Svante
@Svante: "Each of the operators `<`, `>` ... shall yield 1 if the specified relation is true and 0 if it is false"
Stephen Canon
@Svante: not exactly. A value of `0` is "false"; any other value is "true"; however, the relational and equality operators always return `0` or `1` (see Standard 6.5.8 and 6.5.9). -- the value of the expression `a * (x == 42)` is either `0` or `a`.
pmg
Serves me right for typing off the top of my head and not reading the spec. I forgot the special case of zero, assumed it was the same as positive. For most of the places I would use a sign function, that definition would work.
Mark Ransom
Oh ... and the logical negation operator (`!`) also returns 0 or 1. `!!x` is 0 is the value of `x` is 0, 1 otherwise :)
pmg
@Svante: (still about "true" being 1) consider the `is*` functions declared in `<ctype.h>`. 7.4.1/1 "The functions in this subclause return **nonzero (true)** if and only if ...", so not all "boolean" C functions return exclusively 0 and 1.
pmg
http://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign
nthrgeek
As noted below, I'm downvoting this in amazement that (a) someone as smart as Mark Byers is unfamiliar with the C99 language standard and (b) that the SO community prefers this hack to adaptation of copysign() function. OP expressed belief that sign function should be in a standard library or something: it ought to be and it is.
High Performance Mark
High-Performance Mark, I'm amazed that you missed the C++ tag. This answer is very much valid and doesn't deserve a down-vote. Moreover, I wouldn't use `copysign` for integral `x` even if I had it available.
avakar
(X == 0) ? 0 : (X / ABS(X))
Matt Murrell
+1  A: 

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

Tim Sylvester
+2  A: 

Hi

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 +2.0.

Pretty close huh ?

Regards

Mark

High Performance Mark
Not standard, but may be widely available. Microsoft's starts with an underscore, which is the convention they use for non-standard extensions. Not the best choice when you're working with integers, though.
Mark Ransom
copysign is both in the ISO C (C99) and POSIX standards. See http://www.opengroup.org/onlinepubs/000095399/functions/copysign.html
lhf
What lhf said. Visual Studio is not a reference for the C standard.
Stephen Canon
+15  A: 

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)

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

comingstorm
Upvoted this one, downvoted most popular answer. Left reeling in amazement that SO community seems to prefer a hack to use of a standard library function. May the gods of programming condemn you all to trying to decipher hacks used by clever programmers unfamiliar with language standards. Yeah, I know this is going to cost me a ton of rep on SO, but I'd rather side with comingstorm than the rest of you ...
High Performance Mark
This is close, but it gives the wrong answer for zero (according to the Wikipedia article in the question at least). Nice suggestion though. +1 anyway.
Mark Byers
If you want an integer, or if you want the exact signum result for zeros, I like Mark Byers' answer, which is fiendishly elegant! If you don't care about the above, copysign() might have a performance advanage, depending on the application -- if I were optimizing a critical loop, I would try both.
comingstorm
1) C99 is not fully supported everywhere (consider VC++); 2) this is also a C++ question. This is a good answer, but the upvoted one also works, and is more widely applicable.
Pavel Minaev
+1  A: 

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.

ysth
A: 

I tend to use the following:

signval = i/abs(i);

That gives +/- 1 although it's likely not very fast.

DarthNoodles
+1  A: 

And just because you can never have enough different ways to compute a simple value ... The book Hacker's Delight by Henry S. Warren, Jr. describes the sign function on page 19. It gives the the comparison predicate version described by Mark Byers as well as a couple of others. With the Microsoft compiler (v14.00.50727.762), both the /O1 and /O2 switches produce less assembly for the following version from the book:

#define sign1(x) (( x >> 31 ) | ( (unsigned int)( -x ) >> 31 ))

Than for the predicate comparison version:

#define sign2(x) (( x > 0 ) - ( x < 0 ))

It took 3.8 seconds to test 2 billion integers on my PC using sign1. It took 5.7 seconds to test the same values using the comparison predicate version (sign2):

I didn't time it, but gcc (v4.0.2) emitted the same number of assembly instructions both both of these versions of the sign function.

I would be hesitant to use the version with the shift operator, though, unless that small speed improvement was terribly critical. It depends on the signed and unsigned right shift behaving appropriately (not to mention the hard coded assumption on integer size).

Mark Wilkins
See Tim Sylvester's answer for a more portable version.
Stefan Monov
+1  A: 

The OP's question was "C/C++" but here is a strictly c++ solution:

template <typename T>
T sign(T t) 
{
    if( t == 0 )
        return T(0);
    else
        return (t < 0) : T(-1) : T(1);
}

which doesn't handle +/- zero, but uses templates nicely to overload for any type for which the compiler can understand 0, 1, and -1. If it's used on a type for which this isn't true, then the compiler will complain so you don't get unexpected behavior. This wont have the speed of some of the earlier posts, but will be handy for many cases still.

cheshirekow