views:

249

answers:

8

I have a quick question, suppose I have the following code and it's repeated in a simliar way 10 times for example.

if blah then
    number = number + 2^n
end if

Would it be faster to evaluate:

number = number + blah*2^n?

Which also brings the question, can you multiply a boolean value times a integer (Although I am not sure the type that is returned from 2^n, is it an integer or unsigned..etc)? (i'm working in Ada, but let's try to generalize this maybe?)

EDIT: Sorry I should clarify I am looking at 2 to the power of n, and I put c in there cause I was interested for my own learning in the future if I ever run into this problem in c and I think there are more c programmers out there on these boards then Ada (I'm assuming and you know what that means), however my current problem is in the Ada language, but the question should be fairly language independent (I hope).

+1  A: 

If your language allows multiplication between a boolean and a number, then yes, that is faster than a conditional. Conditionals require branching, which can invalidate the CPU's pipeline. Also if the branch is big enough, it can even cause a cache miss in the instructions, though that's unlikely in your small example.

chrisaycock
Interesting, I was thinking about the whole branch thing. I forgot about pipelining (Shame on me, we have been going over it quite a bit in school, I should know better)
onaclov2000
+9  A: 

There is no general answer to such a question, this depends a lot on your compiler and CPU. Modern CPU have conditional move instructions, so everything is possible.

The only ways to know here are to inspect the assembler that is produced (usually -S as compiler option) and to measure.

Jens Gustedt
+4  A: 

I would keep it with the conditional. You shouldn't worry about low-level optimisation details at this point. Write the code that describes your algorithm best and trust your compiler. On some CPUs the multiplication is slower (e.g. ARM processors that have conditionals on each instruction). You could also use the ?: expression which optimises better under some compilers. For example:

number += (blah ? 2^n : 0);

If for some reason this little calculation is the bottleneck of your application after profiling then worry about low-level optimisation.

Cthutu
When doing code reviews for embedded systems, I usually look at written code from the perspective of with little tweaks can it be a little quicker, I'm not planning any kind of massive re-write, or weeks of time tweaking the little things, but just hopefully obvious little things, but perhaps the compiler takes care of this. Although I don't think it can optimize it out, as the data in the boolean is a discrete in this case so it's not known until runtime.
onaclov2000
I would really recommend sticking with a boolean check if your logic is triggered when a condition is true, rather than using an integer/float and multiply it. It will be more obvious to you when you get back to your code in 6 months time.
Cthutu
Be very weary of tweaking for optimisation. You might be making your code harder to read, and worse still make it slower. Intuition is not always your best friend when it comes to optimisation.
Cthutu
@Cthutu based on the comment associated with the function that runs this code, I would be surprise to fail to read the code easily, but I definitely do see your point. I suppose that a quick way to see whether this is quicker or slower (even with the compiler setup) would be to run a similar "function" a bunch of times taking a ton of time measurements, and that should tell me on our particular system whether it's faster or slower.
onaclov2000
I was trying to explain that you should not worry about optimisation at that level and I was describing a general approach, rather anything specific to the example code. Profile your code often and use that as a guide to where you should be focusing your optimisation efforts, should your app need it.
Cthutu
+4  A: 

In C, regarding blah*2^n: Do you have any reason to believe that blah takes the values 0 and 1? The language only promises that 0 <-> FALSE and (everything else) <-> TRUE. C allows you to multiply a "boolean" temporary with another number, but the result is not defined except insofar as result=0 <=> the bool was false or the number was zero.

In Ada, regarding blah*2^n: The language does not define a multiplication operator on type Boolean. Thus blah cannot be a bool and be multiplied.

Eric Towers
I spoke with a co-worker and he mentioned that you can't multiply booleans with numbers. It made sense but I wasn't sure if that was an ada only restriction, or if most languages don't allow.
onaclov2000
Eric: This answer is misleading. The result of a logical/comparison operator in C is **always** 0 or 1. This is well-defined by the standard. You can use other nonzero values with conditionals, but that's quite different from your implication that "true" takes on random nonzero values.
R..
@R..: Hmm... Now you have me trying to remember in which environment I had been surprised to find true (visibly) implemented as -1. I think I recall the "pun" that both !true==false and ~true==false.
Eric Towers
BASIC is most notorious for using -1 as TRUE, I think...
R..
A: 

In either case, you can't avoid a branch (internally), so don't try!

In

number = number + blah*2^n

the full expression will always have to be evaluated, unless the compiler is smart enough to stop when blah is 0. If it is, you'll get a branch if blah is 0. If it's not, you always get an expensive multiply. In case blah is false, you'll also get the unnecessary add and assignment.

In the "if then" statement, the statement will only do the add and assignment when blah is true.

In short, the answer to your question in this case is "yes".

scrapdog
Why is everyone missing the fact that this multiply is not expensive but virtually free? (Hint: it's a power of 2.)
R..
Just because it's a power of two does not make it faster than not doing it at all.
scrapdog
you can avoid the branch it depends on the architecture. you cannot avoid some sort of conditional execution, that is true, unless blah is known to be not just a generic boolean but is specifically a 1 or 0.
dwelch
+5  A: 

In Ada...

The original formulation:

if Blah then
  Number := Number + (2 ** N);
end if;

The alternative general formulation, assuming Blah is of type Boolean and Number and N are of suitable types:

Number := Number + (Boolean'pos(Blah) * (2 ** N));

(For N and Number of user-defined integer or floating point types, suitable definitions and type conversions may be required, the key point here is the Boolean'pos() construct, which Ada guarantees will give you a 0 or 1 for the predefined Boolean type.)

As for whether this is faster or not, I concur with @Cthutu:

I would keep it with the conditional. You shouldn't worry about low-level optimisation details at this point. Write the code that describes your algorithm best and trust your compiler.

Marc C
Nice on the pos part, I didn't think of that. If blah was a predictable value I could understand the compiler piece that both yourself and cthutu say, but since this is a discrete value coming in from a piece of hardware I'm not sure how the compiler can optimize this further, would you (or Cthutu) mind expanding?
onaclov2000
@Marc C: Does Ada really guarantee 0 and 1 for the Boolean type? The only comment on this in the LRM is that False < True. However, I expect this to be the case with most (all?) compilers. And of course, the paranoid can define their own representation for a derived boolean type which guarantees 0 and 1 as the values :)
Schedler
Yes, for predefined Boolean this is guaranteed. It's because of the definition of the 'Pos attribute, which returns the *position number* of the enumeration, i.e. Boolean'Pos(False) is 0, Boolean'Pos(True) is 1. Even if the underlying representations were 0, and something-other-than-0, the 'Pos property would still hold (to get the actual representation you'd have to use an Unchecked_Conversion instantiation to get at it.)
Marc C
If the compiler generates a boolean value, it'll definitely have the appropriate 'Pos behaviour. However, if you generate a "boolean" value using some form of unchecked conversion (eg, importing from C) it may be invalid and most bets are off. For example, with the GCC Ada compiler, 42 can appear to be false in some contexts (because its LSB is clear), true in others, or result in Constraint_Error. As ever, if you're importing from a foreign context, validate at the interface.
Simon Wright
Schedler
+1  A: 

Generaly, and particularly when working with Ada, you should not worry about micro-optimization issues like this. Write your code so that it is clear to a reader, and only worry about performance when you have a problem with performance, and have it tracked down to that portion of the code.

Different CPUs have different needs, and they can be insanely complex. For example, in this case which is faster depends a lot on your CPU's pipeline setup, what's in cache at the time, and how its branch prediction unit works. Part of your compiler's job is to be an expert in those things, and it will do a better job than all but the very best assembly programmers. Certianly better than you (or me).

So you just worry about writing good code, and let the compiler worry about making efficient machine code out of it.

T.E.D.
+2  A: 
dwelch
What about `number += ((blah!=0)` ?
Simon Wright
the result of blah!=0 is either 0 for false or true which is not deterministic.
dwelch
Reading an answer to a similar SO question the standard may dictate that the intermediate comparison does return a 1 or 0, if that is true and the compiler meets that standard everywhere then just do number += (blah!=0)<<n; I am still waiting on a good standard to come out and for a compiler that actually meets any standard so I would rather play it safe. (blah!=0)<<n; should result in three instructions on ARM, so not any faster than if(blah) number += 1<<n; for that architecture. for x86 is should be quite a bit faster.
dwelch