Practice Problems 2 Solutions

  1. Each of the following loops is an attempt to sum up the numbers from 1 to n, e.g.1+2+ ... +n (you can assume n is initialized to some value). For each case, explain why the code doesn’t actually sum the numbers 1 through n.

    a.

     sum = 0
     for i in range(n):
         sum = sum + i
    

    This is close, but recall that range(n) is equivalent to range(0,n) and produce the sequence 0, 1, …, n-1 and so this loop sums 0, 1, …, n-1. It can be fixed as:

     sum = 0
     for i in range(n):
         sum = sum + (i + 1)
    

    b.

     sum = 0
     for i in range(n):
         temp = sum + (i+1)
     sum = temp
    

    Here we’re not updating sum every time through the loop, so each time we access sum in temp = sum + (i+1) the value will still be 0. The final value of temp (and therefor sum) when this code finishes will just be n. It can be fixed as shown above (eliminate temp).

    c.

     sum = 0
     for i in range(n):
         sum = (i+1)
    

    Here we’re are updating sum, but we’re not accumulating. Instead, each time sum will just get i+1. Again, when we’re done, sum will just be n. The loop body needs to be changed to sum = sum + (i+1).

    d.

     sum = 0
     for i in range(n):
         temp = (i+1)
         sum = temp
    

    This is the same problem as c., except now we’ve broken it into two steps, first assigning (i+1) to temp and then temp to sum. Again the loop body needs to be change to accumulate.

  2. Would the following code execute without an error? If so, what would it print?

     for i in range(0):
         print("In the loop")
     print("After the loop")
    

    This code would execute without an error and would just print

     After the loop
    

    range(0) would return an empty sequence (recall the argument is the exclusive end). With an empty sequence the loop body will execute 0 times (i.e., not execute), so print("In the loop") will never execute. It is little weird to explicitly specify a loop that will not execute, but imagine the argument to range was not a fixed value but the result of another computation. We could imagine situations were sometimes we want to loop the execute and sometimes we don’t.

  3. Write a function named factorial that has a single parameter, an integer n, and returns n!, i.e. 1*2*3* ... n.

     def factorial(n):
         """
         Return n factorial for integer argument
         """
         result = 1
         for i in range(n):
             result = result * (i + 1)
         return result
    

    Recall that range(n) starts with 0. Alternately recall that range allows you to specify the start value, so you could implement factorial as:

     def factorial2(n):
         """
         Return n factorial for integer argument
         """
         result = 1
         for i in range(1, n+1):
             result = result * i
         return result
    
  4. Write a docstring for the following function

    Recall from lecture that a docstring should include a brief description of what the function does, what, if any, arguments it expects (i.e. what are its parameters), and what, if any, it returns.

     def mystery():
         """
         Print the first 5 even numbers, one per line
            
         Args:
           None
              
         Returns:
           None
         """
         for i in range(5):
             print(2 + 2*i)
    
  5. Write a function named rand_time that returns a random valid time in HH:MM format as a string. The result can have only a single hour digit, i.e. 1:01 and 10:15 are valid results, but must have two minutes digits, i.e. 1:1 is not a valid result. As a trickier extension, adapt your function to always generate two hour digits, i.e. 1:01 should be represented as 01:01.

     from random import randint
    
     def rand_time():
         """
         Generate a random time in HH:MM format
    
         Args:
           None
    
         Returns:
           Time as a string
         """
         return str(randint(1, 12)) + ":" + str(randint(0, 5)) + str(randint(0, 9))
    

    Note that we need to generate each minutes digit separately to ensure we always get two digits. If we want to do the same for the hours digits as well, we will need to be more sophisticated because the range of the “ones place” depends on the tens place. We can use floor division and modulus to extract those two digits from a randomly generated hour.

     def rand_time2():
         """
         Generate a random time in HH:MM format
    
         Args:
           None
    
         Returns:
           Time as a string
         """
         hours = randint(1, 12)
         return str(hours // 10) + str(hours % 10) + ":" + str(randint(0, 5)) + str(randint(0, 9))
    
  6. Write a function dice_pair that returns the sum of “rolling” two six sided dice, i.e., simulate rolling to two dice and return the sum of the rolled numbers.

     from random import randint
    
     def dice_pair():
         """Return sum of 'rolling' two six sided dice"""
         return randint(1, 6) + randint(1, 6)
    

    Recall that unlike range, both arguments to randint, including the “stop”, are inclusive (whereas range has an exclusive end).