Python Cool Tricks - How to use logical and arithmetic operators together


1. Connection between logical (boolean) and arithmetic operators


When boolean values ​​(or boolean expressions within parentheses) are used in an arithmetic expression, Python converts them to integers, and the False value to 0 and the True value to 1. The reverse is also true: when integers are used in a boolean expression, Python converts them to logical constants (eg x has an integer value, and in the logical expression after the if statement, Python converts it into a logical value and examines whether it is True in the branching statement if x: pass). Based on this, it is possible to write a very short infinite loop, which does nothing useful and will never end, unless you break it with <Ctrl>+<C> or <Ctrl>+<F6>: while 1: pass.

Note: When converting integer to boolean, all values ​​greater than 0 will be True, and the value 0 will be False!


All logical functions can be represented using basic arithmetic operations!


not

x=False, y=not(x), y is True or x=True, y=not(x), y is False.

But how are things arithmetically?

The integer variable x takes only the values ​​0 or 1 and it is necessary that when x is equal to 0 the value of y is 1, and when x is equal to 1 that y is 0. One solution is:

if x==1: y = 0
else: y = 1

Another solution is:

y = 1
if x: y = 0

And the best solution is:

y = 1-x

Note: The need to use the if-else statement is gone!

In case x is a logical variable and has only False or True values, the solution is:

y = True
if x: y = False

Or :

y = bool(1-(x==True))

Note: The need to use the if-else statement is gone!

But it can also be done without using a logical constant:

y = bool(1-int(x))

And it can be even shorter:

y = bool(1-(x))

The expression (x) is actually an abbreviated expression (x==True), but Python also allows without parentheses:

y = bool(1-x)

So:

def not1(x):         # Logical negation
    return bool(1-(x==True))

def not2(x):         # Logical negation
    return bool(1-x)

and

Logical operator AND implemented using basic arithmetic operators:

def round_int(x):     # Rounding a real number to an integer
    if x>=0: x = x + 0.499999999999999
    else: x = x - 0.499999999999999
    return int(x)     # Converting x to an Integer (Trimming Decimals)

def and1(x, y):                # Logical function AND
    if x==True: x1 = 0.5       #  0.0 + 0.0 = 0.0
    else: x1 = 0.0             #  0.0 + 0.5 = 0.5                
    if y==True: y1 = 0.5       #  0.5 + 0.0 = 0.5
    else: y1 = 0.0             #  0.5 + 0.5 = 1.0
    r = round_int(x1 + y1)     # A real number is rounded
    if r==0: b = False
    else: b = True
    return b

def and2(x, y):                # Logical function AND
    return bool(round_int((x==True)/2 + (y==True)/2))

def and3(x, y):                # Logical function AND
    return bool(round_int(x/2 + y/2))

Note: The need to use the if-else statement is gone!


or

Logical operator OR implemented using basic arithmetic operators:

def or1(x, y):                # Logical function OR (inclusive OR)
    if x==True: x1 = 0.51      #  0.0  + 0.0  = 0.0
    else: x1 = 0.0             #  0.0  + 0.51 = 0.51                
    if y==True: y1 = 0.51      #  0.51 + 0.0  = 0.51
    else: y1 = 0.0             #  0.51 + 0.51 = 1.02   
    r = round_int(x1 + y1)     # A real number is rounded
    if r==0: b = False
    else: b = True
    return b

def or2(x, y):                # Logical function OR (inclusive OR)
    return bool(round_int((x==True)/1.99 + (y==True)/1.99))

def or3(x, y):                # Logical function OR (inclusive OR)
    return bool(round_int(x/1.99 + y/1.99))

Note: The need to use the if-else statement is gone!


xor

Python does not have a built-in XOR operator. It is easily implemented using the logical operators NOT, AND and OR:

def xor(x, y):
    return (x or y) and (not(x and y))

Logical operator XOR implemented using basic arithmetic operators:

def xor1(x, y):                # Logical function exclusive OR
    if x==True: x1 = 1         #  abs(0 - 0) = 0
    else: x1 = 0               #  abs(0 - 1) = 1                 
    if y==True: y1 = 1         #  abs(1 - 0) = 1 
    else: y1 = 0               #  abs(1 - 1) = 0
    r = abs(x1 - y1)
    if r==0: b = False
    else: b = True
    return b

def xor2(x, y):                # Logical function exclusive OR
    return bool(abs((x==True) - (y==True)))   

def xor3(x, y):                # Logical function exclusive OR
    return bool(abs(x - y))   

def xor4(x, y):                # Logical function exclusive OR
    return bool((x+y)%2)

def xor5(x, y):                # Logical function exclusive OR
    return bool((x-y)%2)

Note: The need to use the if-else statement is gone!


You must be asking yourself: What should I do with this?

This was all just to better understand the relationship between logical and arithmetic operators.

Now you will see on a simple example how logical and arithmetic operators can be used together. Of course, without using if-else statements!


2. Application of logical and arithmetic operators together


In the simple example that follows, my intention was not to make the best animation of the ball's movement.

The point is to see how the movement of the ball can be controlled, without using if-else statements.

Complete ball motion animation code:

import turtle as tu

DWcol = ['White', 'Pink', 'Red', 'Orange', 'Yellow', 'SandyBrown', 'Lime',
          'Aqua', 'DeepSkyBlue', 'Violet']          # the color of the ball

BGcol = "black"          # background color

x_min = -300             # the smallest value for x within the drawing window
y_min = -300             # the smallest value for y within the drawing window
x_max = 300              # the largest value for x within the drawing window
y_max = 300              # the largest value for y within the drawing window

# definition screen for drawing
tu.screensize(canvwidth=x_max-x_min, canvheight=y_max-y_min, bg=BGcol)

# set the coordinates of the drawing window
tu.setworldcoordinates(x_min, y_min, x_max, y_max)  

def DrawBall(D, col):    # draw a ball of diameter D and color col
    tu.color(col)        # set the draw color to col
    tu.pendown()         # put down the drawing pen
    tu.begin_fill()      
    tu.circle(D)         # draw a circle of diameter D with color col
    tu.end_fill()        # fill the circle with color col
    tu.penup()           # pick up the drawing pen

#tu.bgcolor(BGcol)     # the background is always black
tu.hideturtle()        # hide the drawing pointer
tu.tracer (100, 99)    # ball speed (every 100, 99 will not be displayed)

D = 10              # diameter of the ball in pixels
PS = 50             # the thickness of the edge of the ball
T = 500             # the time the ball is displayed before being deleted in ms
tx = 11             # x-axis movement (acceleration/deceleration of the ball) 
ty = 4              # y-axis movement (acceleration/deceleration of the ball) 
x = 100             # x coordinate of the starting position of the ball
y = 40              # y coordinate of the starting position of the ball
dx = 1              # 1: direc. from left to right, -1: dir. from right to left
dy = 1              # 1: direc. from bottom to top, -1: dir. from top to bottom

x_min += abs(D-PS//2)  # correction because the lot is drawn from below
x_max -= abs(D-PS//2)  # correction because the lot is drawn from below
y_min += 0             # there is no corr. because the lot is drawn from below
y_max -= abs(D-PS//2)+D//2  # correction because the lot is drawn from below +
                            # correction due to the title of the turtle window

tu.pensize(PS)      # set the thickness of the edge of the ball
tu.goto(x, y)       # move the plot to position x,y

for i in range(10000):
    DrawBall(D, DWcol[i%len(DWcol)])  # draw a ball in the drawing color
    tu.delay(T)         # wait T milliseconds
    tu.goto(x, y)       # move the plot to position x,y
    DrawBall(D, BGcol)  # erase the ball by drawing a ball of the backgr. color

    if (x>x_max) or (x<x_min): dx = -dx   # x off screen - change direction
    if (y>y_max) or (y<y_min): dy = -dy   # y off screen - change direction

    x += dx*tx  # The x coord. is increased or decr. (this determines dx) by tx
    y += dy*ty  # The y coord. is increased or decr. (this determines dy) by ty

    tu.goto(x, y)       # move the plot to position x,y

    #print('x =', x, ',  y =', y)  # displays the current x,y coor. of the ball

Controlling the movement of the ball is done using if-else statements:

    if (x>x_max) or (x<x_min): dx = -dx   # x off screen - change direction
    if (y>y_max) or (y<y_min): dy = -dy   # y off screen - change direction

If instead of controlling the movement of the ball using if-else statements, we enter the following code:

    # x off screen - change direction
    dx = -(x>x_max) + dx*(dx==-1) + (x<x_min) + dx*(dx==1)
    # y off screen - change direction
    dy = -(y>y_max) + dy*(dy==-1) + (y<y_min) + dy*(dy==1)

This code can be even shorter:

    dx += -2*dx*(x>x_max) -2*dx*(x<x_min)   # x off screen - change direction
    dy += -2*dy*(y>y_max) -2*dy*(y<y_min)   # y off screen - change direction

Feel free to change the values ​​of variables in the program to get various new effects!


This is a simple example, but in a situation where a large number of if-else statements are used, it is better to use logical and arithmetic operators.


You can find useful information about Python tricks (and other things) on the site:

Python&Math

0
Subscribe to my newsletter

Read articles from Miodrag Golubović directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Miodrag Golubović
Miodrag Golubović

Electrical engineer. He programs in several programming languages. Python because it's relatively lightweight, calculates with very large numbers, has great support and tons of pre-built stuff that you just need to include in your program.