67

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.

perreal
  • 94,503
  • 21
  • 155
  • 181
shanwu
  • 1,493
  • 6
  • 35
  • 45
  • If you know the size of the int you're dealing with, just use a bit-wise "and" to clear the highest-order bit. – Marc B Mar 19 '12 at 14:55
  • 4
    @MarcB: That'll work with sign/magnitude representation (which is fairly unusual) but fail miserably for 1's complement or (by far the most common) 2's complement. – Jerry Coffin Mar 19 '12 at 14:57
  • 1
    @MarcB: It's slightly more involved than that for 2's complement. – Oliver Charlesworth Mar 19 '12 at 14:58
  • it's not a homework, but a question asked by my compiler course instructor. I found it is an interesting question because I've never done it this way before. By the way, solving this problem won't improve my grade for the course, but it will certainly improve my coding skills. ^__^ – shanwu Mar 21 '12 at 12:56
  • can someone explain me why `((n < 0) ? (-n) : (n))` or `((n < 0) ? (n * -1) : (n))` is wrong? – Karthik Chennupati Jan 06 '20 at 18:32
  • @Karthik Chennupati - Ternaries are the same as if and the point of not using if is to generate branch-less machine code. Conditional branches are slow when the CPU's branch predictor can't predict whether or not a branch will be taken, so avoiding them can be faster. – Thorham Feb 09 '20 at 00:34
  • @Thorham - Using a ternary construct as I commented above gave me a wrong answer. Can you please explain to me why it's wrong? – Karthik Chennupati Feb 10 '20 at 05:21
  • Why not use `std::abs()`? –  Nov 05 '20 at 17:58
  • 1
    @adembudak This is a question about branchless programming, a technique for programming without control flow (so no if / else, ternary, or loops) for parts of your code. OP wants to know *how* it's done, not the name of a function that does it. – Adam Jun 24 '21 at 13:14

18 Answers18

55

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;
Hasturkun
  • 35,395
  • 6
  • 71
  • 104
  • I think this is the answer the OP was looking for. – marton78 May 03 '13 at 13:22
  • 3
    v >> sizeof(int) * CHAR_BIT - 1 could you please explain what this does? – codey modey Feb 13 '14 at 02:57
  • 3
    @codeymodey: I didn't write the original, but this depends on 2's complement representation. It makes mask be equal to all 1s if the sign bit is set (since it is being shifted right and this is usually an arithmetic shift, so sign extension occurs). This is equivalent to setting mask to either -1 or 0 according to the sign bit. – Hasturkun Feb 13 '14 at 10:14
  • Okay, but what will this value ...sizeof(int) * CHAR_BIT - 1... be equal to..where is CHAR_BIT defined? – codey modey Feb 14 '14 at 03:05
  • 1
    @codeymodey: `CHAR_BIT` is the number of bits in a char, that's usually 8. It's defined in limits.h. For 32 bit ints this expression returns 31 – Hasturkun Feb 14 '14 at 11:23
  • Maybe I'm missing something, but since this essentially boils down to `r = (v + 0) ^ 0` if v is positive and `r = (v - 1) ^ -1` if v is negative, how could the answers it produces be correct? The former will always be 1 and the latter always a fraction (which would be truncated to 0). – Powerlord Jul 08 '14 at 18:55
  • @Powerlord: Where's the fraction? The only operations involved here are addition and XOR (the `^` operator). See [Two's complement](http://en.wikipedia.org/wiki/Two%27s_complement) for more info, but it boils down to `r = v` if `v` is positive (because XORing something with zero does nothing), and `r = ~v + 1` when negative (since the mask is all 1s, `(x ^ ~0) == ~x`) – Hasturkun Jul 09 '14 at 14:58
  • @Hasturkun *sigh* For whatever reason I was interpreting `^` as an exponent. Guess I was really derping at the time. – Powerlord Jul 09 '14 at 20:39
  • 3
    Isn't right shifting signed ints implementation defined ? Basically we are setting mask = 0x0 for positive and mask=0xffffffff for negative numbers. Isn't "-((unsigned)num>>31)" correct or is it slower ? – Zxcv Mnb Oct 23 '14 at 19:00
  • 1
    @ZxcvMnb: Yes, right shifting signed integers is implementation defined. As I mentioned in a previous comment, this is _usually_ an arithmetic right shift (for instance, [GCC defines this as such](https://gcc.gnu.org/onlinedocs/gcc-4.9.1/gcc/Integers-implementation.html#Integers-implementation)). I don't know if your variation is slower, though it probably requires more operations (i.e. logical shift, negate instead of a single arithmetic shift), in any case, both variations require a 2's complement representation. The linked page has more discussion, which you might find relevant. – Hasturkun Oct 29 '14 at 09:35
  • What advantage does this have over inverting the bits with the bitwise NOT and adding 1? Sure looks like it'd take longer. – MarcusJ Oct 22 '17 at 07:52
  • @MarcusJ: This is done without any branching. It's helpful where branching may be expensive, or the compiler doesn't use specialized instructions for the purpose (e.g. conditional move/negate). As per Bit Twiddling Hacks, `On machines where branching is expensive, the above expression can be faster than the obvious approach, r = (v < 0) ? -(unsigned)v : v, even though the number of operations is the same.`. See also [here](https://godbolt.org/g/16bBTA) for what some variants compile to. – Hasturkun Oct 22 '17 at 09:11
  • Ok, but inverting bits doesn't branch either... and thanks for the condescending tutorial on branching, I already know what that is... Why do you think I searched for branchless versions of abs? – MarcusJ Oct 22 '17 at 09:15
  • @Hasturkun My version is pretty similar to b_abs, except I use a ternary operator to minimize the code (I know that this doesn't stop it from branching), AND my version adds 1 if it needs to be inverted, not sure why yours didn't do that step? but the "branchless" bl_abs version uses 1 more operation, and all the other versions use the same number as regular ol' abs(); – MarcusJ Oct 22 '17 at 09:22
  • @MarcusJ: There's no advantage over doing `~v + 1`, other than this being a NOP when `v >= 0`. As shown by my link, the compiler might make this branchless anyway (as seen on x86-64 gcc, where the compiler clearly knows this trick, but is using `(v ^ mask) - mask)` instead). The hack is useful where you want to force this, but is ultimately just a hack. You usually would have no reason to use this. – Hasturkun Oct 22 '17 at 09:30
  • Yeah yeah yeah, that's taken care of in the it's already positive case, it just returns the value alone. I meant for the signed version. I got a weird result tho, vs my version that I rewrote to use that algorithm, mine uses 1 less instruction than yours in both clang and GCC. https://pastebin.com/d7X3iaVk In fact, BOTH of my versions of the function, the original, and the rewriten-to-be-branchless version, use 1 less instruction on ARM64, MIPS64, and x86_64. – MarcusJ Oct 22 '17 at 09:37
  • After fixing that issue, it's now equal for ARM64, but mine is STILL 1 instruction shorter on x86_64, and MIPS64, using clang 5 for the former and GCC 5.4 for the latter. Updated the pastebin – MarcusJ Oct 22 '17 at 09:52
38
int abs(int v) 
{
  return v * ((v>0) - (v<0));
}

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<0) is false (with a value 0 for false). Hence, when v is positive ((v>0) - (v<0)) = (1-0) = 1. 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<0) is true (value 1). Thus, for negative v, ((v>0) - (v<0)) = (0-1) = -1. And the whole expression is: v * (-1) == -v.

When v == 0, both (v<0) and (v>0) will evaluate to 0, leaving: v * 0 == 0.

Richie Bendall
  • 7,738
  • 4
  • 38
  • 58
perreal
  • 94,503
  • 21
  • 155
  • 181
23

Branchless:

int abs (int n) {
    const int ret[2] = { n, -n };
    return ret [n<0];
}

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.

Sebastian Mach
  • 38,570
  • 8
  • 95
  • 130
  • 10
    "branch-free" in C, may not be once compiled. To be interesting, "branchfree" really is a property of the object code, not of the source. – Steve Jessop Mar 19 '12 at 15:07
  • @SteveJessop: But more seriously: Probably, with any half-decent compiler. However, this is also branchfree in the code structure :) – Sebastian Mach Mar 19 '12 at 15:08
  • well, suppose I'd said "most likely not once compiled". Would I be right or wrong, would it even matter? ;-) – Steve Jessop Mar 19 '12 at 15:09
  • 2
    Nope, and my "may" was of the style of saying the [classy laconian "If."](http://en.wikipedia.org/wiki/Laconic_phrase#Spartan). I think there isn't too much value in the question, and my answer was more an intentionally grunty demonstration :P – Sebastian Mach Mar 19 '12 at 15:14
  • How does the hardware implement the conversion from boolean to integer? Is that done without a conditional branch? – Kerrek SB Mar 22 '12 at 00:06
  • @KerrekSB: I guess there won't be any conversion. The compiler recognizes that the operand is either 0 or 1 (see also 4.7. Integral Conversions), possibly the bool is already of the right indexing size, and ready. – Sebastian Mach Mar 22 '12 at 11:45
15

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.

11

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

flanglet
  • 127
  • 2
4

Try the following:

int abs(int n) 
{
  return sqrt(n*n);
}
Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
Jeremy
  • 97
  • 1
  • 1
  • 4
    sqrt is pretty costly, in addition it accepts double as parameter, so you have 2 conversions (int to double) and (double to int) – dousin Dec 17 '13 at 14:46
  • This actually almost lead me to a solution where I needed an expression where functions were not supported (calculated field in an ADO.Net DataColumn expression). It can also be written as (n*n)^(1/2). Unfortunately power (^) is also not supported... – Louis Somers Jul 07 '17 at 12:32
  • 2
    beside being slow, it'll overflow for larger values of `n`, and it doesn't work correctly if the floating-point type doesn't contain twice the precision of `int` – phuclv Nov 29 '21 at 10:28
3

No branches or multiplication:

int abs(int n) {
    int mask = n >> 31;
    return (mask & -n) | (~mask & n);
}
TurplePurtle
  • 361
  • 2
  • 7
3

Didn't saw this one. For two's complement representation and 32 bit int

( n >> 31 | 1 ) * n
MAG
  • 454
  • 5
  • 14
  • Great solution! This is a better version- ( n >> sizeof(int)*8-1 | 1 ) * n – Minhas Kamal Jan 08 '17 at 18:37
  • @MinhasKamal No. This will fail if `n` is negative and the system zero-fills when using the `>>` operator because `n >> 31` bits will be `0....0001`, causing the "absolute value" to be a negative number. [Per C11 6.5.7p5](https://port70.net/~nsz/c/c11/n1570.html#6.5.7p5): "If E1 has a signed type and a negative value, the resulting value is implementation-defined." – Andrew Henle Aug 01 '23 at 11:51
2

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) << 1)) * a;
}
letiagoalves
  • 11,224
  • 4
  • 40
  • 66
dewang
  • 961
  • 6
  • 2
1

If your language allows bool to int cast (C/C++ like):

float absB(float n) {
    return n - n * 2.0f * ( n < 0.0f );
}
0

There are multiple reasons left shifting the sign bit out and right shifting back in place (v << 1 >> 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 >> 1 does get rid of the sign bit, if there are no padding bits, but the resulting value is the absolute value of v only on systems with sign+magnitude representation, which are vanishingly rare nowadays. On the ubiquitous 2's complement architecture, the resulting value for negative v is INT_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;
chqrlie
  • 131,814
  • 10
  • 121
  • 189
0

What about this one:

#include <climits>

long abs (int n) { // we use long to avoid issues with INT MIN value as there is no positive equivalents.
    const long ret[2] = {n, -n};
    return ret[n >> (sizeof(int) * CHAR_BIT - 1)];    // we use the most significant bit to get the right index.
}
Antonin GAVREL
  • 9,682
  • 8
  • 54
  • 81
0

Bit-shifting is (in principle) implementation-defined, but conversion to a wider signed-integer-type will extend the sign-bit. If you interpret the hi-bits as an integer, they will be 0 or -1, which will let you invert the 2's complement:

int32_t abs(int32_t in)
{
  int64_t in64 = (int64_t)in;
  int32_t* ptr = (int32_t*)&in64;
  int32_t hi = *(++ptr); // assumes little-endian
  int32_t out = (in ^ hi) - hi;
  return out;
}

The above mechanism is the result of compiling the naive implementation with optimization turned on:

mov         eax,ecx  
cdq  
xor         eax,edx  
sub         eax,edx  
caldfir
  • 354
  • 3
  • 7
0

A simple one that avoids bitshifting:

value -= (value < 0) * value * 2;
  • If value is positive, value < 0 evaluates to 0 so the multiplication result is 0. Nothing is subtracted from value.
  • If value is 0, the multiplication result is also 0.
  • If value is negative, value < 0 is true, which evaluates as 1, which is then multiplied by value * 2. Essencially you're subtracting the double of value from value, netting you its corresponding positive.
0

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.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 4
    While technically this answers the question, a ternary is really just a compact if statement, so its probably not what OP is looking for. – Aaron Dufour Mar 19 '12 at 15:15
  • 1
    It uses a different syntax, and returns a value (unlike if), but once compiled still contains a branch, which is generally what people are talking about when they want to avoid `if` statements. This will probably compile to the same machine code as the obvious `if` implementation. – Aaron Dufour Mar 19 '12 at 15:21
  • 1
    @AaronDufour: But the standard does not define the ternary operator to be an if-statement. Actually, unlike if-statements, the ternary operator has a value, and it can yield an lvalue (e.g. `x?y:z = 0;`). What it compiles to is irrelevant. switch-statements may compile to lookup-tables, if-statements may completely dissapear, only the visible behavaiour of the program shall not change (with the exception of RVO) – Sebastian Mach Mar 21 '12 at 15:43
  • 6
    @phresnel But for such a contrived question, the only reasonable interpretation is trying to avoid conditional constructs, which includes both the ternary and `if` statements. Otherwise the question is trivial, as shown in this answer. This is what I was trying to convey with my talk of compiling to branches. – Aaron Dufour Mar 21 '12 at 17:34
  • 3
    @AaronDufour: The title says `without using abs function nor if statement` which to me sounds like it is `if statements` and the `abs`-family of functions which are to be avoided ... – Sebastian Mach Mar 22 '12 at 11:53
  • @phresnel “the ternary operator [...] can yield an lvalue” No. You are thinking of GCC. You cannot do this in standard C. http://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Lvalues.html – Pascal Cuoq Mar 22 '12 at 12:08
  • @Complicatedseebio: Good catch, my mistake. (Sidenote: In C++, it can) – Sebastian Mach Mar 22 '12 at 12:22
  • @Complicatedseebio: Btw, what's with your account? Are you all the same person? – Sebastian Mach Mar 22 '12 at 12:23
  • @phresnel You are right, I guess the admins must have fixed the issue by now and I should update my information. – Pascal Cuoq Mar 22 '12 at 12:39
  • @AaronDufour *But for such a contrived question, the only reasonable interpretation...* As far as I'm concerned, when it comes to contrived questions, just as in love and war, all's fair. Given that this question has 26 answers, it's perfectly reasonable for one of them to use `?:`. Anyone reading can decide for themselves which answers validly conform to the perverse constraint. – Steve Summit Nov 22 '21 at 13:12
-1

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.

Martin
  • 65
  • 8
-1

Use division (and wider math) to form an "if". Perhaps not efficient, yet branchless.

int abs_via_division(int v) {
  // is_neg:0 when v >= 0
  //        1 when v < 0
  int is_neg = (int) ((4LL * v) / (4LL * v + 1));
  return  v * (1 - is_neg*2);
}

Works for all int when long long wider than int, aside from the usual trouble with |INT_MIN|.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
-2

Use the ternary operator:

y = condition ? value_if_true : value_if_false;
Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680