tags:

views:

2687

answers:

9

Instead of using >> and << to shift, is it posible to use * and / to shift left and right?

for an 8-bit: 0x01*2 = 0000|0010?

+5  A: 

You could, but it would be a smart compiler to optimize this into actual bit shifts! Also, if you mean "shift" you better write <<. When you mean 'multiply', write *.

Note that floating points will not shift at all: their exponent will just grow.

xtofl
Smart compiler? That's the sort of optimization every compiler knows about.
Georg
"if you mean "shift" you better write <<. When you mean 'multiply', write *." I fully agree with this point.
mouviciel
there are actually compilers which convert shifts into multiplications to (I guess in order to do more advanced mathematical reductions?), just to convert them back to shifts in the optimizer.
roe
+1  A: 

Yes, you can. Taking your example:

int main() {
  if ((1*2) == (1 << 1)) printf("you certainly can!\n");
  else printf("doesn't work that way\n");
}

And the output it produces:

you certainly can!

See the comments to this response as to why we agreed that (0x01*2 == 0000|0010) is FAR more problematic than ((1*2) == (1 << 1)), a much more concise version.

Chris Bunch
I'm surprised that worked if you really wrote that as 0000|0010. That should have evaluated as 0 octal OR 010 octal, which is 8, and not 2.
Alnitak
that's because it's interpreted like this:((0x01*2 == 0000)|0010)The first term (0x01*2 == 0000) evaluates false, but then you bitwsie OR it with 0010, which is non-zero, and the result is true.You should actually try this expression which will evaluate false(0x01*2 == (0000|0010))
Nathan Fellman
Whoa! That's a real bad example! OR has a higher priority than ==, so this parses to ((0x01*2 == 0000) | 0010). You meant ((0x01*2) == (0000|0010)) which states "doesn't work that way". And you REALLY meant ((0x01*2) == 2) which states "you certainly can!" :)
schnaader
I agree. I certainly learned something today :)
Chris Bunch
And G-Funk actually meant ((1*2) == (1 << 1)) :)
schnaader
Yup, I forgot about the low operator precedence for bitwise operations. The point about octal still stands, though!
Alnitak
+16  A: 

You can of course (for integer math) use multiply by two for a left shift, and a divide by two for a right shift.

You shouldn't do it though.

There are perfectly good left shift and right shift operators, and they do "exactly what they say on the tin". Why confuse your compiler or anyone else reading your code by doing otherwise?

Alnitak
+7  A: 

You should avoid shifting in all cases except when you do bit-operations. Writing << instead of * 2 makes the code less legible. Don't use bit-shifting unless you explicitly want to.

Compilers optimize *2n to << anyway.

Georg
+8  A: 

You can, but why would you want to? Shifting operations are among the things a CPU can do most quickly.

Actually, the opposite is often suggested as a performance optimization: Using shifts to implement multiplication/division by a power of 2.

But any half-decent compiler will do that for you, so you should absolutely not do it manually: keeping your code clear is the most important thing, so use multiplication and division if you're doing math, and use bit shifts if you're manipulating bits.

Michael Borgwardt
+1  A: 

You can,

x << 1 == x * 2
x << 2 == x * 4
etc...

and conversly

x >> 1 == x / 2
x >> 2 == x / 4
etc...

Although I would argue than an experienced c-programmer should be able to look at a bit shifting operation and know that the two methods are analogous. Given the choice I would always use bit shifting as it is clear what your intentions are. If you did use the multiplication / or division option you would clearly need to comment why you are suddenly multiplying values by seemingly random numbers. Whereas the bit shifting clearly documents that you are trying to shift bits.

As for any optamization comments, unless absolutely necessary e.g. time critical emebedded programming, I wouldn't overly worry about optamization of your code. Code readability and maintainability should be your focus, not optamization! If at the end of development, you need more performance, you can always go back and do the optamization (making sure you carefyully document eveverything you do!). But during development, I would go for what is the easiest to read and maintain e.g. using '<<' / '>>'.

TK
Also, the computer will optimize out most multiplies and divides by constant integers to shit+add operations anyway.
Adam Hawes
+3  A: 

Yes, except for one gotcha: division may work differently to right shifting when dealing with negative numbers. The behaviour of right shifts on negative numbers is compiler defined.

You can of course avoid this issue by using unsigned integers.

As others have said, a modern compiler will probably produce the same output whether you use shifts or multiplication/division. So use whatever makes the code easier to follow and maintain.

Artelius
A: 

All others have said it's perfectly possible to do. It's also pointless. If you mean to shift then shift. If you mean to multiply then multiply. Don't confuse the reader of your code with useless "optimization".

An aside from the Question:

Your compiler will look at any integer multiply/divide by a constant amount and reduce the expression to a series of shift/add operations almost all of the time. It does this because binary multiplication is not an easy task, and it takes a lot longer than shifts and adds, which can be completed in a singe clock cycle once they are passed into the ALU. Interesting the integer multiplier in a CPU does roughly similar but in an automated way - it's still slightly faster to use individual shift/add operations because you don't need to stop and test conditions for every level of shifting you're doing.

I could draft the basic algorithm into here for you, but it's nearly midnight so you can google it. If there's enough call for it I'll edit the post and put it in tomorrow.

This optimization is particularly true of multiplies by constants of the 2^n variety, because it's a single shift operation.

Adam Hawes
A: 

Yes you can always replace shifts with power of 2 multiplications but as has been pointed out, why?. What hasn't been pointed out is that it is sometimes useful to replace multiplication with shifting and not just for simple powers of 2. For example in the good ol' days with 320 * 200 pixel buffers the offset to a pixel byte was y*320+x. This could be done as follows:

int OffsetXY( int x, int y)
{
    int offset;

    y <<= 6;
    offset = y;
    offset += y << 2;  // offset = original y * 320
    return offset + x;
}

While this sort of is only of academic interest to most developers now, it can be useful in the embedded world (did some coding recently on the DS and this kind of thing was useful).

Tim Ring