Please help, possible combination of 1, 2 and 3

Hi,
I am a bit confused about why my code is not running properly. I want to print out all of the possible combinations of 1, 2 and 3. For example, 123 and 231 are some possible outcomes. I coded it in Java and it worked but not in python. Here is my code:
for a in range(1,4):
for b in range(1,4):
for c in range(1,4):
if a!=b & a!=c & b!=c:
print(a,b,c)

Can anyone be kind enough to leave me a message where my code is wrong? Thanks.

I am a bit confused about why my code is not running properly. I want
to print out all of the possible combinations of 1, 2 and 3. For
example, 123 and 231 are some possible outcomes. I coded it in Java and
it worked but not in python. Here is my code:

for a in range(1,4):
for b in range(1,4):
for c in range(1,4):
if a!=b & a!=c & b!=c:
print(a,b,c)

Ah. This is a subtle bug to do with operator precedence.

Discussion below.

Can anyone be kind enough to leave me a message where my code is wrong? Thanks.
![Screenshot (2)|690x388]…

Please do not post screenshots. Paste the result of the run in the
message directly as text. Those of us reading this as email get things
instantly when the output is inline.

Anyway, my run of your code did this:

1 2 3
2 1 3
3 1 2
3 2 1

Just like yours. I was surprised, expecting six results (3 x 2 x 1).

The obvious unusualness in your code is that Python uses “and” for
logical conjunction, not “&”, which is a bitwise binary operator between
numbers.

I still expected it to work, because True and False (from “a!=b” et al)
do work with the bitwise operators, treating them as 1 and 0
respectively: 1 & 1 is 1 (with is true in Python), 1 & 0 is 0 (which is
false in Python). until I thought more precisely.

So, what’s really happening?

As you will know from arithmetic, various operators have various
“precedence”; some bind more tightly that others. When you write:

3 * 2 + 1

do you expect 7 or 9 as the answer? Without brackets, most people expect
7 because we bind “*” (multiplication) more tightly than “+” (addition),
which means that we evaluate:

(3 * 2) + 1

and not:

3 * (2 + 1)

Loosely speaking, the rule of thumb here is that “more powerful”
functions like multiplication bind more tightly that “less powerful”
functions like addition. Similarly exponentiation binds more tightly
still.

In programming languages this is always laid out formally somewhere.
Here it is for Python:

https://docs.python.org/3/reference/expressions.html?highlight=precedence#operator-precedence

But in general:

  • comparison operators such as < or != have lower precedence than
    arithmetic
  • the logical operators such as “and” and “or” have lower precedence
    than comparisons

This allows you to write:

3 + 2 < 7 and 4 * 2 > 7

and have it read like this:

( (3 + 2) < 7 ) and ( (4 * 2) > 7 )

which you would hope.

So, back to your test:

if a!=b & a!=c & b!=c:

By using “&” (binary/bitwise AND) instead of “and” (logical AND) you
have chosen an operator with higher precence than a comparison,
because “&” is a type of arithmetic. So your if-statement reads like
this:

if a != (b & a) != (c & b) != c:

which is legal because Python supports chained comparisons, such as “3 <
5 < 7” as a short way to write “3 < 5 and 5 < 7”. So your if-statement
is equivalent to:

if (
    a != (b & a)
and (b & a) != (c & b)
and (c & b ) != c
):

For added fun, because the values 1, 2 and 3 have the binary
representations 0b01, 0b10 and 0b11, the various combinations of (b&a)
and (c&b) produce various zero and nonzero results. Eg 0b10 & 0b01
equals 0b00 (false).

As as such, more of your permutations are excluded (not printed) than
you expect.

All this is because of precedence (the grouping of the expressions) and
use of binary operators ("&") instead of logical operators (“and”).

If you had written:

if a != b and a != c and b != c:

the grouping would be:

if (a != b) and (a != c) and (b != c):

which is what you intended.

Cheers,
Cameron Simpson cs@cskk.id.au

1 Like