# -*- coding: utf-8 -*- """ Created on Wed Sep 30 12:28:51 2020 @author: jbobowsk """ # This tutorial will demonstrate some implementations of nested control # structures in Python. Nested structures very quickly become complicated # and hard to decipher. Python requires you to indent your code properly # which is an advantage because it makes the code easier to read/follow. # In the while loop tutorial we should how you could calculate factorials # using while loops. Suppose you wanted to restrict users to inputing only # integer values of n. You can do this by placing your while loop inside # an if statement. The if statement will be used to check for valid # values of n. # First, I introduce the % function. y % x outputs the remainder of # y/x. x = 5 % 2 print(x) x = 4 % 2 print(x) # We can use n % 1 to check that n is an integer. x = 5.2 % 1 print(x) x = 5 % 1 print(x) # So, here is our first nested set of control structures. n = 4.3 if n % 1 == 0: print('n =', n) factorial = 1 while n > 1: factorial = factorial*n n -= 1 print('n! =', factorial) else: print('Invalid entry: n is noninteger.') # Notice that we can still trick the system into producing nonsense by # entering a negative integer. n = -4 if n % 1 == 0: print('n =', n) factorial = 1 while n > 1: factorial = factorial*n n -= 1 print('n! =', factorial) else: print('Invalid entry: n is noninteger.') # To fix this problem, we need to check that n is an integer AND positive. # We will use 'and' to add another condition to our if statement. # We will also implement some elseif statements so that we can present proper # error messages. # # In the elseif statements != means 'not equal to' and <= means 'less than # or equal to'. Try different entries for n. If you enter, for example, a # string for n you'll get an error message from Python. As you can see, # accounting for all the possible silly inputs users could enter requires a # lot of thorough and careful programming! n = 13 if n % 1 == 0 and n > 0: print('n =', n) factorial = 1 while n > 1: factorial = factorial*n n -= 1 print('n! =', factorial) elif n == 0: print('n =', n) print('n! = 1') elif n % 1 != 0 and n > 0: print('Invalid entry: n is noninteger.') elif n % 1 == 0 and n < 0: print('Invalid entry: n negative.') elif n % 1 != 0 and n < 0: print('Invalid entry: n is noninteger and negative.') # Now let's put our factorial code into a for loop so that we can calculate # n! as a function of n. import numpy as np start = 0 finish = 25 ns = np.arange(start, finish + 1, 1) print(ns) facts = [] for i in ns: if i % 1 == 0 and i > 0: n = int(i) factorial = 1 while n > 1: factorial = factorial*n n -= 1 facts = facts + [factorial] elif i == 0: facts = facts + [1] elif i % 1 != 0 and n > 0: print('Invalid entry: n is noninteger.') elif i % 1 == 0 and n < 0: print('Invalid entry: n negative.') elif i % 1 != 0 and n < 0: print('Invalid entry: n is noninteger and negative.') print(facts) # We can now easily make a plot of n! vs n. Notice how sharply n! rises. import matplotlib.pyplot as plt plt.plot(ns, facts, 'bo', fillstyle = 'none') plt.ylabel('n!') plt.xlabel('n') plt.title('linear-linear plot') # Here's the same data on a log-log scale. plt.figure() plt.loglog(ns, facts, 'ro', fillstyle = 'none') plt.ylabel('n!'); plt.xlabel('n') plt.title('log-log plot') # Here, we compare n! to exp(n). Above about n = 5, n! passes exp(n) and # continues to increase at a higher rate than exp(n). xx = np.arange(1, finish, 0.01) yexp = np.exp(xx) plt.loglog(xx, yexp, 'k--') plt.legend(('n!', 'exp(n)')) # Finally, here's an implementation of our nested control structures in # which the user is prompted to enter in start and end values for the n! # calculation and then the plot comparing n! and e^n is generated. start = int(input("Enter an integer start value: ")) finish = int(input("Enter an integer end value: ")) ns = np.arange(start, finish + 1, 1) facts = [] for i in ns: if i % 1 == 0 and i > 0: n = int(i) factorial = 1 while n > 1: factorial = factorial*n n -= 1 facts = facts + [factorial] elif i == 0: facts = facts + [1] elif i % 1 != 0 and n > 0: print('Invalid entry: n is noninteger.') elif i % 1 == 0 and n < 0: print('Invalid entry: n negative.') elif i % 1 != 0 and n < 0: print('Invalid entry: n is noninteger and negative.') plt.figure() plt.loglog(ns, facts, 'ro', fillstyle = 'none') plt.ylabel('n!'); plt.xlabel('n') plt.title('log-log plot') xx = np.arange(start, finish, 0.01) yexp = np.exp(xx) plt.loglog(xx, yexp, 'k--') plt.legend(('n!', 'exp(n)'))