Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » logical vs. binary operators

This thread is locked; no one can reply to it. rss feed Print
 1   2 
logical vs. binary operators
Martin Kalbfuß
Member #9,131
October 2007
avatar

Hi,

I realised that the the logical operators && and || are doing the same as & and |.

int res1 = 5 == 5 && 3 < 4
int res2 = 5 == 5 & 3 < 4

return the same result. I always used them without thinking about their difference. So why do I need extra operators for logical operations?

Thanks

http://remote-lisp.spdns.de -- my server side lisp interpreter
http://www.nongnu.org/gm2/ -- Modula-2 alias Pascal++

anonymous
Member #8025
November 2006

Short circuiting on logical operators. And you have to be careful to use the binary operators only with boolean values or you won't get the same results.

#SelectExpand
1#include <stdio.h> 2 3int one() { return 1; } 4int two() { return 2; } 5 6int main() 7{ 8 if (one() && two()) { 9 puts("Ok with logical and"); 10 } 11 if (one() & two()) { 12 puts("Ok with binary and"); 13 } 14 return 0; 15}

Matthew Leverton
Supreme Loser
January 1999
avatar

& is binary:

0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1

So if both sides of (foo == 1) & (bar == 2) evaluate to true, then the expression is true. But that only works with boolean values. Consider:

if (1 & 2) {
  // not true
}

if (1 && 2) {
  // true
}

Also, logical operators will short circuit.

#SelectExpand
1int t() 2{ 3 return 1; 4} 5 6int f() 7{ 8 fire_nukes(); 9 return 0; 10} 11 12if (t() || f()) 13{ 14 // world is safe ... f() never called 15} 16 17if (t() | f()) 18{ 19 // world is blown up 20}

They are used for different things ... although many times they are interchangeable.

Arthur Kalliokoski
Second in Command
February 2005
avatar

Or to rephrase:


001001001 binary A
bitwise or'ed with (|)
000100001 binary B
---------
001101001  Return all bits that are set as in "Is this particular bit set in A or B?"
Not the same as asking little Tommy if he wants cake OR ice cream for dessert and he 
says "Yes" (Exclusive OR is what was wanted there)

001001001 binary A
logically or'ed with {||)
000100001 binary B
---------------
NNYYNYNNY   <- where N means neither bit is set, and Y means at least one bit is set,
and Yes overrides No.  Since one or more Yes'es are there, return TRUE or 1.

They all watch too much MSNBC... they get ideas.

Tobias Dammers
Member #2,604
August 2002
avatar

I realised that the the logical operators && and || are doing the same as & and |.

They don't.

int a = 2 & 4;
int b = 2 && 4;

printf("a = %i", a);
printf("b = %i", b);

The logical operators evaluate each operand as a boolean, perform their logic on them, and return a boolean.
The binary operators evaluate each operand as an integer, perform their logic on individual bits, and return an integer.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

tobing
Member #5,213
November 2004
avatar

Oops.

& is a bit-wise operation on the operands, i.e. the result has a bit set only if both operands have the same bit set.

&& is a logical operation on two bool values and is true only if both operands evaluate to true.

| is a bit-wise operation, a bit in the result is set if the corresponding bit is set in one of both operands.

|| again is a logical operation between two bool operands.

So considering the bit-representation of numbers, you get 5 | 8 = 13, 5 | 7 = 5, 5 & 8 = 0, 5 & 7 = 5.

ImLeftFooted
Member #3,935
October 2003
avatar

I think | is always the same as ||... (in a condition)

Kitty Cat
Member #2,815
October 2002
avatar

|| gives a boolean result, | gives an integer..

if((a || b) == (c || d)) ...
// vs
if((a | b) == (c | d)) ...

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

Audric
Member #907
January 2001

Dustin: If both operands are booleans (only values 0x00000001 and 0x00000000), and if there are no side effects of evaluating the right one, and if you only care if the result equals zero; then yes, you get the same result.

Note that under the same conditions, + is the same as ||

ImLeftFooted
Member #3,935
October 2003
avatar

Audric said:

Note that under the same conditions, + is the same as ||

I dunno, not really.

if(UINT_MAX + 1)
  // nope

While

if(UINT_MAX | 1)
  // yup

My main point was that he probably thought | -> || and & -> && were equivalent because effectively | -> || really is. It would be logical (without knowing more) that & would expand to && as well, especially because it does if you're lucky.

Arthur Kalliokoski
Second in Command
February 2005
avatar

Doesn't C++ require Booleans to be 1... uh, or 0 exclusively? 4 | 6 isn't the same as 4 || 6 then.

They all watch too much MSNBC... they get ideas.

Jonatan Hedborg
Member #4,886
July 2004
avatar

| still does not short circuit.

Kitty Cat
Member #2,815
October 2002
avatar

Doesn't C++ require Booleans to be 1... uh, or 0 exclusively?

From what I remember being told, bools in C++ are not numbers, but are either true or false. Nothing else. False is interpreted as integer 0 (same as NULL is interpreted as integer 0, even if the NULL address is not 0x00000000), and true is a non-0 integer. Most compilers will use 1, but -1 and 124354245 are just as valid.

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

Arthur Kalliokoski
Second in Command
February 2005
avatar

Sorry, I was misremembering what I'd read in http://www.agner.org/optimize/optimizing_cpp.pdf.

Quote:

Boolean variables are stored as 8-bit integers with the value 0 for false and 1 for true.
Boolean variables are overdetermined in the sense that all operators that have Boolean
variables as input check if the inputs have any other value than 0 or 1, but operators that
have Booleans as output can produce no other value than 0 or 1. This makes operations
with Boolean variables as input less efficient than necessary.
...
This is of course far from optimal. The branches may take a long time in case of
mispredictions (see page 38). The Boolean operations can be made much more efficient if it
is known with certainty that the operands have no other values than 0 and 1. The reason
why the compiler doesn't make such an assumption is that the variables might have other
values if they are uninitialized or come from unknown sources.

They all watch too much MSNBC... they get ideas.

Audric
Member #907
January 2001

Dustin: I said "under the same conditions".... UINT_MAX is not equal to 0x00000001 or 0x00000000.

Unrelatedly, here are two valid uses of the operators, where you really shouldn't mistake one for the other.

// Use high quality sprite if available, or use the normal one.
// (If there was a big problem, none is available, so use a generic "missing" sprite)
BITMAP *sprite = high_quality_sprite || normal_quality_sprite || sprite_missing;

...

// Store multiple related booleans in a single field.
this->Collision_flags = COLLISION_SOLID | COLLISION_GRAVITY | COLLISION_PUSHABLE;

Kitty Cat
Member #2,815
October 2002
avatar

Audric said:

BITMAP *sprite = high_quality_sprite || normal_quality_sprite || sprite_missing;

This won't do what you think it does.

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

Audric
Member #907
January 2001

What did I miss ? Associativity is left-to-right, I just checked. I admit it's not a construct I actually use, so I'd rather know what's the mistake.

Arthur Kalliokoski
Second in Command
February 2005
avatar

You're messing with the address of the bitmap struct location, not setting attributes.

They all watch too much MSNBC... they get ideas.

Jonatan Hedborg
Member #4,886
July 2004
avatar

That should not matter. If the first one is zero, the next one will be returned (etc). I can't see why that would fail... Though I only ever used it in actionScript and ruby.

Audric
Member #907
January 2001

Arthur Kalliokoski: That was my intention... the two examples are not necessarily related. When I wrote the second I was tempted to rewrite the first as "this->sprite = ...", but then you wouldn't see that the type of "sprite" is "BITMAP *", and this seemed required for understanding...
My example relies on the fact that NULL is the only value of a pointer that "is not true".

Tobias Dammers
Member #2,604
August 2002
avatar

Doesn't C++ require Booleans to be 1... uh, or 0 exclusively? 4 | 6 isn't the same as 4 || 6 then.

No. It requires boolean false to evaluate to zero when cast to integer, and boolean true to something non-zero. 1 is common, but AFAIK any other non-zero value would be valid too. The important thing is that when you cast a boolean to int and then back to boolean, the original value must be retained.
4 | 6 returns 6, 4 || 6 returns true. If you interpret the result as a boolean, both are equivalent, but not if you interpret them as integers.

The most important point IMO however is readability. Use the distinction between logical and bit-wise operator to clearly indicate your intention, even if they happen to be interchangeable.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Matthew Leverton
Supreme Loser
January 1999
avatar

That should not matter. If the first one is zero, the next one will be returned (etc). I can't see why that would fail... Though I only ever used it in actionScript and ruby.

printf("%d\n", 10 || 20 || 30);

What do you expect that to display (in C/C++)?

Correct Answer: 1

Jonatan Hedborg
Member #4,886
July 2004
avatar

Oh that's intresting. Never tried it in C/C++, just assumed it worked as in other languages :)

Thomas Fjellstrom
Member #476
June 2000
avatar

Indeed boolean operators evaluate to a boolean value. ie: 0 or 1.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Ron Novy
Member #6,982
March 2006
avatar

It's simple when you think about it like this. Boolean operators are either equal to 0 (FALSE) or not equal to zero (TRUE)... So any value that is not zero is TRUE.

#SelectExpand
1int x = 0; /* == FALSE */ 2int y = 10; /* == TRUE */ 3int z = -30; /* == TRUE */ 4 5if (x) 6 printf("x == 1 == TRUE\n); // <- This string is never displayed because x == 0 7 8if (z) 9 printf("z == 1 == TRUE\n"); // <- z evaluates to TRUE or 1 (same with y). 10 11if (x || y) 12 printf("x || y == 1 == TRUE\n"); 13 14if (x && y) 15 printf("x && y == 1 == TRUE"); // <- This string is never displayed... 16 17if (!x && z) 18 printf("!x && z == TRUE\n"); // <- !x == 1 and z == 1 so this is displayed.

Bottom line is, the two types of OR and AND operators should not be confused with each other. You will get unexpected results...

[edit]Arg... I was too slow...

----
Oh... Bieber! I thought everyone was chanting Beaver... Now it doesn't make any sense at all. :-/

 1   2 


Go to: