Intro to
Programming
(with Python)

Fall 2019
course
site

Tue Oct 15

Discuss the "functions" homework

Discuss midterm project topics

asides

The death of files | hackernews discussion

What's new in python 3.8 | hackernews discussion

In class we looked at the attached example.py and special.py files.

Decisions & Booleans - chap 7 & 8 material

Today over the next class or two we'll discuss the material in these two chapters.

Here are Zelle's classroom slides for this material :

more ways to loop

See the attached average4a.py as an example of some of these ideas.

boolean algebra

(not x) and (not y)    # which of these are the same ?
not (x and y)
not (x or y)

Well ... let's check.

layout = " {:6}  {:6}   {:16}  {:16} "

print(layout.format('a', 'b', 'not (a and b)', '(not a) or (not b)'))
print(layout.format('-'*6,'-'*6, '-'*16, '-'*16))

for a in (True, False):
    for b in (True, False):
        print(layout.format(str(a), 
                            str(b), 
                            str(not (a and b)), 
                            str((not a) or (not b))))

which outputs this

 a       b        not (a and b)     (not a) or (not b) 
 ------  ------   ----------------  ---------------- 
 True    True     False             False            
 True    False    True              True             
 False   True     True              True             
 False   False    True              True     

In the next homework I'm going to ask you to do something similar for DeMorgan's laws.

short-circuit evaluation

Most programming languages - including python - have a "short circuit" behavior that let's you use "and" and "or" to accomplish the same sort of decision making that is more typically done with "if" statements : pay_up() or suffer_the_consequences().

This will take a bit of explaining.

def t():
  print("in t")
  return True

def f():
  print("in f")
  return False

for expression in ['f() and t()',
                   't() and f()',
                   'f() or t()',
                   't() or f()']:
  print('-- {} --'.format(expression))
  print(eval(expression))

which produces

-- f() and t() --
in f
False
-- t() and f() --
in t
in f
False
-- f() or t() --
in f
in t
True
-- t() or f() --
in t
True

The first and last case terminate without making the second function call. These constructions can be used to accomplish something like an "if" construction, in the sense of "We better leave now or we'll miss our train."

In the first case, since f() is false, (f() and t()) must be false, so t() isn't evaluated.

In the last case, since t() is true, (t() or f()) must be true, and so t() isn't evaluated.

An example often used in the perl programming language in constructions like open(filename) or die('cannot open file') in which open() returns False if it cannot, and die() is a built-in that prints an error message and exits the program.

This conditional evaluation means that in python, "and" and "or" are not just purely logical operators ... and so for example deMorgan's laws don't always work.

bitwise operators - optional

Python (and most programming languages) also has "bitwise" logic operators which treat numbers as binary sequences of 0's and 1's, where each 0 means "false" and each one means "true".

The bitwise operator does a bunch of boolean operations on each bit, to produce a new sequence of bits.

The operators are

&   bitwise  "and"
|   bitwise  "or"
~   bitwise  "not"
^   bitwise  "xor"  (exlusive or)
<<  shift bits left  (i.e. multiply binary number by 2)
>>  shift bits right (i.e. divide binary number by 2

For example

>>> a = 3     #   011 in base 2
>>> b = 5     #   101 in base 2
>>> a | b     #   (011 | 101) => (0 or 1)(1 or 0)(1 or 1) => 111
7
>>> a & b     #   (011 & 101) => (0 and 1)(1 and 0)(1 and 1) => 001
1

These are typically used for manipulating the individual bits within binary data, which isn't what we'll be doing this term. They are important when working at the assembler level of computer systems, down at the "low level" near the hardware.

Lewis Carroll puzzles - optional

One amusing example of the sort of logic we're doing this week are Lewis Carroll puzzles ...

(1) Every one who is sane can do Logic;
(2) No lunatics are fit to serve on a jury;
(3) None of your sons can do Logic.
What conclusion can be drawn?
Use
 a = able to do Logic
 b = fit to serve on a jury
 c = sane
 d = your sons

Express each line as a boolean expression. Then use the rules of boolean algebra to draw a short conclusion.

Answer: None of your sons is fit to serve on a jury.

How can we do that using logic rules? python??

These sorts of puzzles are largely based on the "implies" boolean operator, which isn't one commonly used in typical programming practice. It's usually written with an arrow

a → b

and is pronounced "a implies b", which means "if A is True, then B is True". As a boolean operator, it's truth table is

 a      b        a → b
 -----  -----    -----
 True   True     True
 True   False    False
 False  True     True
 False  False    True

which turns out to be the same as (not a) or b.

def implies(a, b):
    return (not a) or b
 a      b        a → b
 -----  -----    -----
 True   True     True
 True   False    False
 False  True     True
 False  False    True

logic gates - optional

Computer chips themselves are made of "logic gates", which are small devices which implement boolean operations. Typically "true" is "high voltage" and "false" is "low voltage" in a semiconductor thingy.

For example, and "and gate" is a device with two inputs and one output. Here's one in mouser's catalog.

 a_in   ---%%%%%%%%
           % gate %---  c_out
 b_in   ---%%%%%%%%

It's possible to hook up these things into networks to do things like addition ... or to be the CPU of a computer.

Here's an adder circuit.

You can even build logic gates with mechanical parts - tinker toys for example - and hook them up into networks to do interesting things ... like play tic tac toe

It's possible to construct all the logical operations, including "not", "and", and "or", from a single logic gate: the NAND gate, which implements "not and".

def nand(a,b):
    return not(a and b)

Its truth table looks like this.

 a      b        nand(a, b)
 -----  -----    ----------
 True   True     False
 True   False    True
 False  True     True
 False  False    True

That means that in principle, you can build an entire computer system out of just NAND gates and some clocks to get send signals through the network sequentially ... which is actually done in the book and course From Nand to Tetris: Building a Modern Computer from First Principles.

I've thought about offering that as a course at here at M'boro but haven't yet. The materials and software for "Nand to Tetris" are extensive - it might be possible to do it as a group tutorial.

https://cs.marlboro.college /cours /fall2019 /python /notes /chap8
last modified Sat April 27 2024 12:10 am

attachments [paper clip]

  last modified size
TXT average4a.py Sat Apr 27 2024 12:10 am 908B
TXT example.py Sat Apr 27 2024 12:10 am 1.0K
TXT special.py Sat Apr 27 2024 12:10 am 917B