views:

646

answers:

4

I want to implement a logical operation that works as efficient as possible. I need this truth table:

p    q    p → q
T    T      T
T    F      F
F    T      T
F    F      T

This, according to wikipedia is called "logical implication"

I've been long trying to figure out how to make this with bitwise operations in C without using conditionals. Maybe someone has got some thoughts about it.

Thanks

+7  A: 
!p || q

is plenty fast. seriously, don't worry about it.

eduffy
That's not bitwise!
Chris Dolan
who cares.. a bitwise operation will not be any faster than that.
eduffy
Yes, actually I wanted to know also if this would be as fast as bitwise. Thanks for claryfing me that.
alvatar
For a 32-bit int, "~p | q" does 32 times as much work as "!p || q" and doesn't require a jump.
Chris Dolan
litb: jumps are slower than arithmetic in just about every CPU due to branch prediction misses.
Chris Dolan
Chris, good point :D
Johannes Schaub - litb
Great. Maybe you can edit your answer adding this info. I think is very interesting.
alvatar
Agreed. I know I was unaware of it. Also, what do you mean by "jump"?
Dinah
Chris, yeah that's what i was on. || sequences so that q is evaluated after !p in any case. tho if p and q are normal bools, chances are good that it compiles down to code as fast as ~p | q i think.
Johannes Schaub - litb
Dinah, short circuit stuff.
Johannes Schaub - litb
Dinah: By jump, I mean that the CPU has to decide whether to execute the next opcode or branch to another point in the program. See http://en.wikipedia.org/wiki/Branch_prediction
Chris Dolan
The bitwise operator is not 32 times as fast. It's one clock cycle per calculation either way. No difference in performance.
eduffy
unless q is volatile, there is no need for a branch if both variables are simple integers.
Johannes Schaub - litb
eduffy: by 32 times as fast, I meant that you get 32 boolean results in parallel instead of one boolean result.
Chris Dolan
+9  A: 
~p | q

For visualization:

perl -e'printf "%x\n", (~0x1100 | 0x1010) & 0x1111'
1011

In tight code, this should be faster than "!p || q" because the latter has a branch, which might cause a stall in the CPU due to a branch prediction error. The bitwise version is deterministic and, as a bonus, can do 32 times as much work in a 32-bit integer than the boolean version!

Chris Dolan
Thanks! I would like to ask where could I get more information about these? I mean about the C implementation of these operations, so I can get to know the details of || vs | and so on...
alvatar
Maybe http://en.wikipedia.org/wiki/Bitwise_operation
Chris Dolan
i've tested both versions. GCC at least on x86 insists on using a branch returning 0/1 for the bool version in every scenario i could imagine. bitwise ops did not.
Johannes Schaub - litb
+5  A: 

FYI, with gcc-4.3.3:

int foo(int a, int b) { return !a || b; }
int bar(int a, int b) { return ~a | b; }

Gives (from objdump -d):

0000000000000000 <foo>:
   0:   85 ff                   test   %edi,%edi
   2:   0f 94 c2                sete   %dl
   5:   85 f6                   test   %esi,%esi
   7:   0f 95 c0                setne  %al
   a:   09 d0                   or     %edx,%eax
   c:   83 e0 01                and    $0x1,%eax
   f:   c3                      retq   

0000000000000010 <bar>:
  10:   f7 d7                   not    %edi
  12:   09 fe                   or     %edi,%esi
  14:   89 f0                   mov    %esi,%eax
  16:   c3                      retq

So, no branches, but twice as many instructions.

@litb: Ok, here is with _Bool:

0000000000000020 <baz>:
  20:   40 84 ff                test   %dil,%dil
  23:   b8 01 00 00 00          mov    $0x1,%eax
  28:   0f 45 c6                cmovne %esi,%eax
  2b:   c3                      retq

So, using _Bool instead of int is a good idea.

derobert
Or you could just use `gcc -S *.c; cat *.s` and skip the `objdump -d *.o` step? ;-)
ephemient
Yeah, but I remembered the objdump option but not the gcc one :-p
derobert
Actually, testing gcc -S it gives /much/ more output, all of the extra stuff irrelevant.
derobert
I get much shorter code for the || version with _Bool (c99) or bool (c++)
Johannes Schaub - litb
this is insane. with optimizations off, the bitwise way stays that short, while the || way bloats all the way up :p
Johannes Schaub - litb
well, if you want fast code, it'd be pretty silly to compile without optimizations. I used -O3
derobert
+3  A: 

You can read up on deriving boolean expressions from truth Tables (also see canonical form), on how you can express any truth table as a combination of boolean primitives or functions.

vladr
Very interesting link. Thanks!
alvatar