views:

358

answers:

10
int aNumber;

aNumber = aValue / 2;
aNumber = aValue >> 1;

aNumber = aValue * 2;
aNumber = aValue << 1;

aNumber = aValue / 4;
aNumber = aValue >> 2;

aNumber = aValue * 8;
aNumber = aValue << 3;

// etc.

Whats is the "best" way to do operations? When is better to use bit shifting?

+15  A: 

The two are functionally equivalent in the examples you gave (except for the final one, which ought to read aValue * 8 == aValue << 3), if you are using positive integers. This is only the case when multiplying or dividing by powers of 2.

Bit shifting is never slower than arithmetic. Depending on your compiler, the arithmetic version may be compiled down to the bit-shifting version, in which case they both be as efficient. Otherwise, bit-shifting should be significantly faster than arithmetic.

The arithmetic version is often more readable, however. Consequently, I use the arithmetic version in almost all cases, and only use bit shifting if profiling reveals that the statement is in a bottleneck:

Programs should be written for people to read, and only incidentally for machines to execute.

fmark
agreed. start with the arithmetic, until your code works and is bug free. then dig down and use bit shifting as one of the tools in your toolbag to optimize for performance.
pxl
Also you may want to look at the optimised assembly output .. I believe some compilers will translate simple arithmetic to shifts when optimising.
Michael Anderson
for simple stuff, a compiler may find it and optimize. but what it won't do is alter your algorithm with bitshifting in mind. and for that, you have to put your binary hat on.
pxl
A good example of this kind of optimizations are high performance math libraries. I saw situations where division was branched using an if statement - if the divisor was a power of two it would go into the shifting branch, otherwise would use regular arithmetic. This of course makes sense only with repeated divisions with the same divisor (in an algorithms etc.).
PeterK
I think that also there is a good example of why you should more often go for the arithmetic version given the error in the question. More thought is required to get your bit shifting right...
Paddy
A: 

If you have big calculations in a tight loop kind of environment where calculation speed has an impact --- use bit operations. ( considered faster than arithmetic operations)

aJ
This is premature optimisation (which is the root of all evil). Use the natural expression of what you are doing. If you are logically dividing by 8 (for example), use the arithmetic operation. If you are logically trying to shift out the low byte use bit shifts. The reason is that modern compilers will automatically convert multiply and divide by powers of two into shift operations for you.
JeremyP
Bit operations might be considered faster as machine operations on some hardware platforms. They are *not* "considered faster" neither as C nor as C++ language-level operations. Those who do this kind of "considering" simply confuse machine operations with language operations.
AndreyT
A: 

When its about power 2 numbers (2^x), its better to use shifts - it's just to 'push' the bits. (1 assembly operation instead of 2 in dividing).

Is there any language which its compiler does this optimization?

rursw1
On what platform is int divide two assembly instructions?
Pete Kirkham
See my comment to aJ's answer.
JeremyP
gcc x86 does even at -O0.
Pete Kirkham
@Pete on 6502 integer divide is many more than two operations - there is no integer divide. Still, I'm unaware ogf an Objective-C compiler for 6502, so it's probably irrelevant.
JeremyP
All cpus I know/have seen have a single instruction division. The problem is that division is slower than shift, not that it is performed by one more instruction. Shifting a register is faster since the involved circuits are very simple, while those of a division are much more complex.
ShinTakezou
@ShinTakezou : remember the good all days or old-fashioned cpus or simply still used (where?) division-lacking cpus... :) ... I think all cpus currently used for real in everyday devices (except washing machines and similar) have the div instruction
ShinTakezou
+3  A: 

Bit shifting is a 'close to the metal' operation that most of the time doesn't contain any information on what you really want to achieve.

If you want to divide a number by two, by all means, write x/2. It happens to be achieved by x >> 1, but the latter conceals the intent.

When that turns out to become a bottleneck, revise the code.

xtofl
+8  A: 

The difference is that arithmetic operations have clearly defined results (unless they run into signed overflow that is). Shift operations don't have defined results in many cases. They are clearly defined for unsigned types in both C and C++, but with signed types things quickly get tricky.

In C++ language the arithmetical meaning of left-shift << for signed types is not defined. It just shifts bits, filling with zeros on the right. What it means in arithmetical sense depends on the signed representation used by the platform. Virtually the same is true for right-shift >> operator. Right-shifting negative values leads to implementation-defined results.

In C language things are defined slightly differently. Left-shifting negative values is impossible: it leads to undefined behavior. Right-shifting negative values leads to implementation-defined results.

On most practical implementations each single right-shift performs division by 2 with rounding towards negative infinity. This, BTW, is notably different from the arithmetic division / by 2, since typically (and always in C99) of the time it will round towards 0.

As for when you should use bit-shifting... Bit-shifting is for operations that work on bits. Bit-shifting operators are very rarely used as a replacement for arithmetic operators (for example, you should never use shifts to perform multiplication/division by constant).

AndreyT
Especially since the compiler is very likely to optimize your arithmetical operation with bit-shifts operators if you use constants.
Matthieu M.
@Matthieu M.: It is even more likely that the compiler will optimize it with operations that are neither immediately arithmetic nor shifts.
AndreyT
A: 

As long as you are multiplying or dividing within the 2er powers it is faster to operate with a shift because it is a single operation (needs only one process cycle).
One gets used to reading << 1 as *2 and >>2 as /4 quite quickly so I do not agree with readability going away when using shifting but this is up to each person.

If you want to know more details about how and why, maybe wikipedia can help or if you want to go through the pain learn assembly ;-)

Mark
+2  A: 

Whats is the "best" way to do operations?

Use arithmetic operations when dealing with numbers. Use bit operations when dealing with bits. Period. This is common sense. I doubt anyone would ever think using bit shift operations for ints or doubles as a regular day-to-day thing is a good idea.

When is better to use bit shifting?

When dealing with bits?

Additional question: do they behave the same in case of arithmetic overflow?

Yes. Appropriate arithmetic operations are (often, but not always) simplified to their bit shift counterparts by most modern compilers.

Edit: Answer was accepted, but I just want to add that there's a ton of bad advice in this question. You should never (read: almost never) use bit shift operations when dealing with ints. It's horrible practice.

David Titarenco
+2  A: 

When your goal is to multiply some numbers, using arithmetic operators makes sense.

When your goals is to actually logically shift the bits, then use the shift operators.

For instance, say you are splitting the RGB components from an RGB word, this code makes sense:

 int r,g,b;
 short rgb = 0x74f5;
 b = rgb & 0x001f;
 g = (rgb & 0x07e0) >> 5;
 r = (rgb & 0xf800) >> 11;

on the other hand when you want to multiply some value with 4 you should really code your intent, and not do shifts.

Toad
+1  A: 

As an example of the differences, this is x86 assembly created using gcc 4.4 with -O3

int arithmetic0 ( int aValue )
{
    return aValue / 2;
}

00000000 <arithmetic0>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   8b 45 08                mov    0x8(%ebp),%eax
   6:   5d                      pop    %ebp
   7:   89 c2                   mov    %eax,%edx
   9:   c1 ea 1f                shr    $0x1f,%edx
   c:   8d 04 02                lea    (%edx,%eax,1),%eax
   f:   d1 f8                   sar    %eax
  11:   c3                      ret    

int arithmetic1 ( int aValue )
{
    return aValue >> 1;
}

00000020 <arithmetic1>:
  20:   55                      push   %ebp
  21:   89 e5                   mov    %esp,%ebp
  23:   8b 45 08                mov    0x8(%ebp),%eax
  26:   5d                      pop    %ebp
  27:   d1 f8                   sar    %eax
  29:   c3                      ret    

int arithmetic2 ( int aValue )
{
    return aValue * 2;
}

00000030 <arithmetic2>:
  30:   55                      push   %ebp
  31:   89 e5                   mov    %esp,%ebp
  33:   8b 45 08                mov    0x8(%ebp),%eax
  36:   5d                      pop    %ebp
  37:   01 c0                   add    %eax,%eax
  39:   c3                      ret    

int arithmetic3 ( int aValue )
{
    return aValue << 1;
}

00000040 <arithmetic3>:
  40:   55                      push   %ebp
  41:   89 e5                   mov    %esp,%ebp
  43:   8b 45 08                mov    0x8(%ebp),%eax
  46:   5d                      pop    %ebp
  47:   01 c0                   add    %eax,%eax
  49:   c3                      ret    

int arithmetic4 ( int aValue )
{
    return aValue / 4;
}

00000050 <arithmetic4>:
  50:   55                      push   %ebp
  51:   89 e5                   mov    %esp,%ebp
  53:   8b 55 08                mov    0x8(%ebp),%edx
  56:   5d                      pop    %ebp
  57:   89 d0                   mov    %edx,%eax
  59:   c1 f8 1f                sar    $0x1f,%eax
  5c:   c1 e8 1e                shr    $0x1e,%eax
  5f:   01 d0                   add    %edx,%eax
  61:   c1 f8 02                sar    $0x2,%eax
  64:   c3                      ret    

int arithmetic5 ( int aValue )
{
    return aValue >> 2;
}

00000070 <arithmetic5>:
  70:   55                      push   %ebp
  71:   89 e5                   mov    %esp,%ebp
  73:   8b 45 08                mov    0x8(%ebp),%eax
  76:   5d                      pop    %ebp
  77:   c1 f8 02                sar    $0x2,%eax
  7a:   c3                      ret    

int arithmetic6 ( int aValue )
{
    return aValue * 8;
}

00000080 <arithmetic6>:
  80:   55                      push   %ebp
  81:   89 e5                   mov    %esp,%ebp
  83:   8b 45 08                mov    0x8(%ebp),%eax
  86:   5d                      pop    %ebp
  87:   c1 e0 03                shl    $0x3,%eax
  8a:   c3                      ret    

int arithmetic7 ( int aValue )
{
    return aValue << 4;
}

00000090 <arithmetic7>:
  90:   55                      push   %ebp
  91:   89 e5                   mov    %esp,%ebp
  93:   8b 45 08                mov    0x8(%ebp),%eax
  96:   5d                      pop    %ebp
  97:   c1 e0 04                shl    $0x4,%eax
  9a:   c3                      ret    

The divisions are different - with a two's complement representation, shifting a negative odd number right one results in a different value to dividing it by two. But the compiler still optimises the division to a sequence of shifts and additions.

The most obvious difference though is that this pair don't do the same thing - shifting by four is equivalent to multiplying by sixteen, not eight! You probably would not get a bug from this if you let the compiler sweat the small optimisations for you.

aNumber = aValue * 8;
aNumber = aValue << 4;
Pete Kirkham
A: 
int i = -11;
std::cout << (i  / 2) << '\n';   // prints -5 (well defined by the standard)
std::cout << (i >> 1) << '\n';   // prints -6 (may differ on other platform)

Depending on the desired rounding behavior, you may prefer one over the other.

FredOverflow