I was thinking how to get the absolute value of an integer without using if
statement nor abs()
. At first I was using shift bits left (), trying to get negative sign out of the range, then shift bits right back to where it be, but unfortunately it doesn't work for me. Please let me know why it isn't working and other alternatives ways to do it.
问题:
回答1:
From Bit Twiddling Hacks:
int v; // we want to find the absolute value of v unsigned int r; // the result goes here int const mask = v >> sizeof(int) * CHAR_BIT - 1; r = (v + mask) ^ mask;
回答2:
Branchless*:
int abs (int n) { const int ret[2] = { n, -n }; return ret [n
Note 4.7 Integral Conversions / 4: [...] If the source type is bool, the value false is converted to zero and the value true is converted to one.
*: In the sense that there is no conditional branching in your code. Under the hood, the ternary operator will also produce a branch. However, it's also a valid answer, because the ternary one isn't an if-statement. This doesn't imply that your compiler isn't able to emit branchfree assembly code for code that logically branches.
回答3:
int abs(int v) { return v * ( (v0)); // simpler: v * ((v>0) - (v
This code multiplies the value of v
with -1
or 1
to get abs(v). Hence, inside the parenthesis will be one of -1
or 1
.
If v
is positive, the expression (v>0)
is true and will have the value 1
while (v is false (with a value 0 for false). Hence, when
v
is positive ((v>0) - (v. And the whole expression is:
v * (1) == v
.
If v
is negative, the expression (v>0)
is false and will have the value 0
while (v is true (value 1). Thus, for negative
v
, ((v>0) - (v. And the whole expression is:
v * (-1) == -v
.
When v == 0
, both (v and
(v>0)
will evaluate to 0, leaving: v * 0 == 0
.
回答4:
Assuming 32 bit signed integers (Java), you can write:
public static int abs(int x) { return (x + (x >> 31)) ^ (x >> 31); }
No multiplication, no branch.
BTW, return (x ^ (x >> 31)) - (x >> 31);
would work as well but it is patented. Yup!
Note: This code may take more then 10x longer then conditional statement (8bit Verison). This may be useful for Hardware programming System C etc
回答5:
Bit shifting signed integers in the way you consider is undefined behaviour and thus not an option. Instead, you can do this:
int abs(int n) { return n > 0 ? n : -n; }
No if
statements, just a conditional expression.
回答6:
I try this code in C, and it works.
int abs(int n){ return n*((2*n+1)%2); }
Hope this answer will be helpful.
回答7:
Here is another approach without abs()
, if nor any logical/conditional expression: assume int is 32-bit integer here. The idea is quite simple: (1 - 2 * sign_bit)
will convert sign_bit = 1 / 0 to -1 / 1
.
unsigned int abs_by_pure_math( int a ) { return (1 - (((a >> 31) & 0x1)
回答8:
Didn't saw this one. For two's complement representation and 32 bit int
( n >> 31 | 1 ) * n
回答9:
Try the following:
int abs(int n) { return sqrt(n*n); }
回答10:
Use the ternary operator:
y = condition ? value_if_true : value_if_false;
回答11:
how about that:
value = value > 0 ? value: ~value + 1
its based on the fact that negative numbers are stored as 2's complement to there positive equivalent, and that one can build the 2's complement by first building the 1's complement and adding 1, so
5 -> 0000 0101b -5 -> (1111 1010b) + 1 -> 1111 1011b
what I did was basically to reverse this, so
-5 -> 1111 1011b 5 -> (0000 0100b) + 1 -> 0000 0101b
I know it's a bit late but just had the same issue and landed here, hope this helps.
回答12:
One more way to do it:
int abs(int n) { int mask = n >> 31; return (mask & -n) | (~mask & n); }
Using the (mask & A) | (~mask & B)
pattern. Not sure if it has a name. I call it a bitwise branch.
回答13:
If your language allows bool to int cast (C/C++ like):
float absB(float n) { return n - n * 2 * (n
回答14:
There are multiple reasons left shifting the sign bit out and right shifting back in place (v > 1
):
- left shifting a signed type with a negative value has undefined behavior so it should not be used at all.
- casting the value to
unsigned
would have the desired effect:(unsigned)v > 1
does get rid of the sign bit, if there are no padding bits, but the resulting value is the absolute value ofv
only on systems with sign+magnitude representation, which are vanishingly rare nowadays. On the ubiquitous 2's complement architecture, the resulting value for negativev
isINT_MAX+1-v
Hasturkun's solution unfortunately has implementation defined behavior.
Here is a variation that is fully defined for systems with 2's complement representation for signed values:
int v; // we want to find the absolute value of v unsigned int r; // the result goes here unsigned int mask = -((unsigned int)v >> (sizeof(unsigned int) * CHAR_BIT - 1)); r = ((unsigned int)v + mask) ^ mask;
回答15:
You have to combine bitwise not and addition.
回答16:
What's wrong with just:
-1 * n
Using the minus minus equals plus principle
回答17:
if you want a purely mathematical way that isn't too costly, try
f(x) = (x*x)/x
or in C++
function abs(auto x) {return ((x*x)/x);}