tags:

views:

506

answers:

10

What are the differences between

int size = (int)((length * 200L) / 100L); // (1)

and

int size = length << 1; // (2)

(length is int in both cases)

I assume both code snippets want to double the length parameter.

I'd be tempted to use (2) ... so are there any advantages for using (1)? I looked at the edge cases when overflow occurs, and both versions seem to have the same behavior.

Please tell me what am I missing.

+2  A: 

This sounds like premature optimizations. The plus for just doing length * 2 is that the compiler most certainly optimizes this and it's easier to maintain.

simendsjo
A: 

Below link gives detailed discussion on the same with moral being that computer does not perform multiplication by calling addition repeatedly.

http://stackoverflow.com/questions/3060064/how-computer-multiplies-2-numbers

So the answer of computer using repeated addition for multiplication is wrong.

ckv
Multiplication is definitely *not* implemented by repeated addition.
Greg Hewgill
yes i have upated the answer based on the answers to separate question on the same. Can the downvote be revoked.
ckv
As far as I can see, you haven't changed your answer. You're still stating *"multiplication is nothing but calling addition repeatedly"*
Philippe Leybaert
+20  A: 

And here is the 3rd option:

int size = length * 2; // Comment explaining what is 2 or what means this multiplication

And this must be the best option. As it is readable and easy to understand what you want to do. As for performance, compilers are generating pretty optimized code, so no need to worry for such a simple operation. If you have any concerns concerning overflow you can use checked block.

EDIT As mentioned by many others just use any meaningful variable instead of 2 here.

Incognito
I think `length * 2' is actually worse than the first option. Your proposal describes the intend of the code less. There is a forth option, which I think is better. He should use named constants instead of `200L` and `100L'. This does a much better job in describing the code's intent.
Steven
And what is the advantage of the 4th option ? If there is a concern for the overflow checked block will be enough.
Incognito
@Incognito: I'm sorry, my comment wasn't very clear. I don't believe performance is not an issue here, because compiler will optimize. Both your option and mine. You comment on readability and I agree that readability is very important, but don't think `length * 2` is most readable. There is probably a reason for doing that calculation. Therefore, I think using named constants is better for performance. btw. I was a bit too eager in down voting you. Can you edit your comment. This is the only way for me to undo this down vote.
Steven
"There is probably a reason", that's the ultimate example of unreadable code.
Hans Passant
@Steven: No worries :) I have edited the answer. Anyway you have the right point about magic numbers.
Incognito
@Everyone: If someone can't figure out what `length * 2` is, they have brain damage. This whole bit about readability is a load of crap. Multiplying anything by any integral number is DROP DEAD EASY to read: multiply 'thing' by a factor of '#'. You MAY be able to make it "more obviously understandable" by using a constant: `const int SCALE_FACTOR = 2; int size = length * SCALE_FACTOR;` However, this has the problem of requiring readers to go figure out what SCALE_FACTOR is if they wish to know what they are multiplying by. There is no guarantee the constant's location is well known.
jrista
@Everyone: There is a fifth option that makes the intent of "not easily understandable" code easy to understand, constants or not: its called a comment.
jrista
@jrista +100 for comments for such simple cases. Answer is updated.
Incognito
@incognito: HA! Thanks. ;) I guess I was a little harsh. To me, it boils down to what gives you the mot benefit for your fretting. You can fret over a trivial one-liner like this for hours, arguing about readability and understandability when a comment will solve the problem....OR, you can spend those hours solving much larger problems...like those *Big Balls of Mud* littering your code (no, wait, it IS your code)...or the thing that somewhere that is absolutely destroying performance...or those missing features that your customers are threatening to ditch you over...Yeah...... `length * 2`...
jrista
@jrista: There is no guarantee that `SCALE_FACTOR` is well known, but there is also no guarantee that the justification for "multiply by 2" is well known. As a simple rule of thumb, if it the justification for multiplying by 2 (rather than 3 or 4) is based on local information, then a magic number is probably overkill.
Brian
+1  A: 

With any modern compiler left shift by 1 or multiplying by 2 will generate the same code. It's probably going to be an add instruction adding the number to itself, but it depends on your target.

On the other hand, doing (x*200)/100 will not be the same as doubling the number since the first multiplication may overflow, so this cannot be optimized safely to doubling the number.

augustss
+7  A: 

Which is more readable to your average programmer:

int size = length * 2;
int size = length << 1;

Unless they come from a strong C++ bit tweaking background I'd wager your average programmer knows immediately what the first line does (it even has the number "2" for "double" in it) but would have to stop and pause for the second line.

In fact I'd feel inclined to comment the second line explaining what it does which seems redundant when you can get the code do the talking as in the first line.

Graphain
If somebody needs a comment explaining the shift operator that somebody shouldn't be programming at all in my eyes.
Because you're presumably from a c/c++ background. In my eyes any use of the shift operator is an over-optimisation. I could take that first line to a person on the street and they could guess what it does. Try that with the second line. If the programmer couldn't work it out in 5 seconds then I might be concerned but that's just unnecessary extra thinking for no conceivable benefit.
Graphain
@Graphain: Do you ask people from the street to write your software, or do you hire programmers? I do agree with you, but ToxicAvenger has a very good point.
Ant
He really doesn't. You can program without the shift operator just as easily as you can program without the ternary operator. And you're turning my argument into a straw-man - I'm not suggesting our goal is to make our programs readable to those on the street, but if there are two ways of doing something and the only difference is clarity it makes sense to pick the clearer one. Code should convey intent.
Graphain
If I ran to our server or mobile device team they could tell it in a second (C/C++ programmers). If I were to ask it to our Desktop (C#) team I'm sure that half of them would have to look it up. How many times do you need a bitshift to program a gui?...
Carra
@Graphain: If there are programmers who aren't familiar with the very basic operators, then you are making them a favor by making them look it up. I fully agree with you on principle of simplicity, but for God's sake, bit shifting operator? Isn't it CS 101?
ya23
At the end of the day, the goal of software is to solve problems, not be internally beautiful or super-optimized. While I'd agree that the second is "more pure" in the theory sense, the first is far and away easier to read - there's no sense harking back to the way it used to be as an justification for using the more obfuscated form for this operation. They both do exactly the same thing, and I'll bet the compiler knows it. Using the "exclusive" version of the operation serves no purpose.
rwmnau
In my opinion, programmers' arrogance is one of the greatest hindrances in software development, and to teamwork in general.
Phong
@ya23, I think you're taking too hard-lined of an approach, at this point it is entirely possible to be a software developer without ever having to worry about the notation for an implementation of a bit shift. It is yet again something that as long as the reasoning behind it is understood then the implementation in practice means absolutely nothing, not matter how much you want your code to be optimized for bad compilers.
Jean-Bernard Pellerin
@Jean-Bernard Pellerin: Correct. I'm not defending the code in this particular case, just the given argument. The code shouldn't be there because it's a micro-optimalization (of course unless there is a specific, measured need for it). But saying it's so hard to read it requires a comment? Nowadays it's possible to be a software developer knowing only very basic syntax of just one programming language. Does it mean we should all dumb down the code so junior programmers won't have to learn delegates and generics?
ya23
+2  A: 

What do 200L and 100L represent? Seems to me you are using magic numbers. You should try to write your program in such a way that it describes its intent as good as possible; making it as readable as possible. Using named constants for these values instead of magic numbers is a good way of doing this. Also extracting the calculation in its own well named method helps too. When you do this, you will immediately see that there is no way of rewriting it to x << 1. Not because the results will be different, but because maintainability will suffer. When you write code like x << 1, the next programmer has no idea what that actually means and it will increase the famous WTFs per minute:

alt text


I think your code should look more like this:

int size = CalculateThingSize(length);

private static int CalculateSizeOfThing(int length)
{
    const long TotalArraySize = 200L;
    const long BytesPerElement = 100L;

    return (length * TotalArraySize) / BytesPerElement;
}

Of course the names of these const values are a wild guess :-)

Steven
the 200L / 100L is not my own code ... I just stumbled upon it and asked about _sematic_ differences (which I think there might be, since (1) casts to long). This is not a beauty contest. So I guess your answer is just a bit off the mark.
+22  A: 

The idea that << is faster than multiplication is reasoning as though the .NET jit compiler is actually a poorly optimized C compiler written in the 1970's. Even if it were true, the difference would be measured in picoseconds at this point in time, even if there were a difference, which there probably is not.

Write code so that it is easy to read. Let the compiler take care of the pico-optimizations. Optimize your code based on profiling realistic scenarios, not on second guessing what the compiler will generate.

Furthermore, the shift operators do not have the same semantics as multiplication. For example, consider the following sequence of edits:

Original program by Jill:

int x = y * 2;

Edit by Bob: Silly Jill, I'll make this "faster":

int x = y << 1;

Edit by Larry the Intern: Oh, we have a bug, we're off by one, let me fix that:

int x = y << 1 + 1;

and Larry has just introduced a new bug. y * 2 + 1 is different than y << 1 + 1; the latter is actually y * 4.

I have seen this bug in real live production code. It is very easy to mentally get into the mindset that "shifting is multiplication" and forget that shifting is lower precedence than adding, whereas multiplication is higher precedence.

I have never once seen someone get arithmetic precedence wrong who multiplied by two by writing x * 2. People understand the precedence of + and *. Lots of people forget what the precedence of shifting is. Are the picoseconds you don't actually save worth any number of potential bugs? I say no.

Eric Lippert
I'm glad someone pointed this out. I like the word "pico-optimizations". In our language we call this "bitneuken" (can't translate it, or I will get banned :-)
Philippe Leybaert
I am surprised that so many people think that `x << 1` is less readable than `x * 2`. If I want to multiply by a power of 2, I usually use shift, because it actually constrains the multiplicand, so states the intend even better. And how do you write values for your `[Flags]` enums??? Surely you use either hex or shift, not denary???
@ToxicAvenger: You can't compare bitmapped flags with simple multiplication. If you want to multiply by 32, it's a LOT more readable to say value*32 instead of value<<5. Bitshift operators have their use, but not for multiplying. What if you had to change your code later to value*31?
Philippe Leybaert
Right. The claim is not that bitshifting is justified because it is more readable but rather that it is justified because it is faster. I say it doesn't matter which is faster: when the operation you want is logically *multiplying a number* then *multiply*. When the operation you want is logically *manipulating bits* then *manipulate bits*. When you treat a number as a bit array, you're operating at the wrong level of abstraction. The fact that numbers are implemented as bit arrays should not be taken advantage of unless there is a *compelling* reason to do so.
Eric Lippert
Removed. Would open another can of worms. Good night.
+10 for "When you treat a number as a bit array, you're operating at the wrong level of abstraction.". Eric is -as always- spot on.
Steven
+2  A: 

It's interesting that most of the answers argue that the compiler will optimise a multiply by a power of 2 into a bitshift. It's obvious that none of the responders have actually tried compiling a bitshift versus a multiply to see what the compiler actually produces.

This is purely an academic exercise; as just about everyone has pointed out, the multiply is easier to read (though quite why the "*200L / 100L" part is in there is anyone's guess - that just serves to obfuscate things). It's also pretty obvious that replacing a multiply with a bitshift in C# isn't going to have any significant performance increase, even in tight loops. If you need that kind of optimisation, you're using the wrong platform and language to start with.

Let's see what happens when we compile a simple program with CSC (the C# compiler) included with Visual Studio 2010 with optimisations enabled. Here's the first program:

static void Main(string[] args)
{
    int j = 1;

    for (int i = 0; i < 100000; ++i)
    {
        j *= 2;
    }
}

Using ildasm to decompile the resultant executable gives us the following CIL listing:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       23 (0x17)
  .maxstack  2
  .locals init ([0] int32 j,
           [1] int32 i)
  IL_0000:  ldc.i4.1
  IL_0001:  stloc.0
  IL_0002:  ldc.i4.0
  IL_0003:  stloc.1
  IL_0004:  br.s       IL_000e
  IL_0006:  ldloc.0
  IL_0007:  ldc.i4.2
  IL_0008:  mul
  IL_0009:  stloc.0
  IL_000a:  ldloc.1
  IL_000b:  ldc.i4.1
  IL_000c:  add
  IL_000d:  stloc.1
  IL_000e:  ldloc.1
  IL_000f:  ldc.i4     0x186a0
  IL_0014:  blt.s      IL_0006
  IL_0016:  ret
} // end of method Program::Main

Here's the second program:

static void Main(string[] args)
{
    int j = 1;

    for (int i = 0; i < 100000; ++i)
    {
        j <<= 1;
    }
}

Decompiling this gives us the following CIL listing:

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       23 (0x17)
  .maxstack  2
  .locals init ([0] int32 j,
           [1] int32 i)
  IL_0000:  ldc.i4.1
  IL_0001:  stloc.0
  IL_0002:  ldc.i4.0
  IL_0003:  stloc.1
  IL_0004:  br.s       IL_000e
  IL_0006:  ldloc.0
  IL_0007:  ldc.i4.2
  IL_0008:  shl
  IL_0009:  stloc.0
  IL_000a:  ldloc.1
  IL_000b:  ldc.i4.1
  IL_000c:  add
  IL_000d:  stloc.1
  IL_000e:  ldloc.1
  IL_000f:  ldc.i4     0x186a0
  IL_0014:  blt.s      IL_0006
  IL_0016:  ret
} // end of method Program::Main

Note the difference at line 8. The first version of the program uses a multiply (mul), whilst the second version uses a left-shift (shl).

Quite what the JIT does to it when the code is executed I'm not sure, but the C# compiler itself demonstrably does not optimise multiplies by powers of two into bitshifts.

Ant
well that is the IL. I think bigger parts of the optimizations happen in the JIT, so you would need to look at the assembly code generated by the JIT and make sure all optimizations are enabled (DEBUG in VS for example generates some attributes which manipulate the behavior and you can also manipulate the JIT behavior by ini file). Based on my experience, looking at the IL helps little to none when talking about "pico"-optimizations.
The fact that the C# compiler doesn't optimize, doesn't mean that the JIT compiler won't. A decent JIT compiler will optimize the code it generates. After all, what the C# compiler generates is just intermediate code.
Philippe Leybaert
If you compile x * 2; and x << 1; in c, you get equivalent assembly (shift arithmetic left for both), which is probably why most people are saying that the compiler will optimize the multiplication. Clearly the C# compiler does not (at least for your example) but the JIT might.
Niki Yoshiuchi
A: 

To answer your actual question, there appears to be no behavior differences between those two snippits of code, when length is a non-negative int and the code text is within an unchecked context.

Within a checked context (int.MaxValue * 200L) will never overflow because the result easily fits within a long. (int)((length * 200L) / 100L will only overflow when length * 2 overflows. Under no circumstances will a shift operator overflow. Therefore, the code snippits behave differently within a checked context.

If length is negative, then the shift operation will produce incorrect results, while the multiplication will work correctly. Therefore, the two code snippits are different if the length variable is allowed to be negative.

(Contrary to popular opinion x << 1 is not the same as x * 2. They are only the same if x is an unsigned integer.)

Jeffrey L Whitledge
+1  A: 

When I see the idiom:

int val = (someval * someConstant) / someOtherConstant;

I think that the code's intent is to do scaling in some manner. It could be manual fixed point code or it could be avoiding problems with integer division. A concrete example:

int val = someVal * (4/5); // oops, val = 0 - probably not what was intended

or written to avoid going back and forth to floating point:

int val = (int)(someVal * .8); // better than 0 - maybe we wanted to round though - who knows?

when I see this idiom:

int val = someVal << someConstant;

I briefly wonder if the individual bits in someVal have some deeper meaning that requires the shifting and then I start looking at surrounding context to understand why it was done this way.

The thing to remember is that when you are writing code that has something like this:

int val = expr;

that there are an infinite number of ways to create expr such that val will always have the same value. It is important to consider what intent you are expressing in expr for those who will follow.

plinth