Solutions: You can find the file with solutions for all questions here.

Review from lab

Call Expressions

A call expression applies a function, which may or may not accept arguments. The call expression evaluates to the function's return value.

The syntax of a function call:

  add   (    2   ,    3   )
   |         |        |
operator  operand  operand

Every call expression requires a set of parentheses delimiting its comma-separated operands.

To evaluate a function call:

  1. Evaluate the operator, and then the operands (from left to right).
  2. Apply the operator to the operands (the values of the operands).

If an operand is a nested call expression, then these two steps are applied to that operand in order to evaluate it.

Introduction to Functions

First, we will explain what exactly a function is.

Sometimes, we need to use a bundle of code over and over again. For example, converting fahrenheit to celsius! Which you coded in the first lab.

It would be exhausting to have to write ((fahrenheit - 32)*5)/9 Every time we want to convert fahrenheit to celsius. So, we bundle it up into a function:

# the below line is what we call the “function definition”
# it states the name of the function and its parameters/arguments, which is
# “fahrenheit” # in this case. 
# a parameter is something that a function takes in and uses in some way.
def converter(fahrenheit):
    return ((fahrenheit - 32)*5)/9

Now every time we want to do a conversion, we can call just the converter function:

converter(54)

This is abstraction. We abstract the expression into a convenient function that can be used for any input values.

Return Statement

Most functions that you define will contain a return statement. The return statement will give the result of some computation back to the caller of the function and exit the function. For example, the function square below takes in a number x and returns its square.

def square(x):
    """
    >>> square(4)
    16
    """
    return x * x

Problems

Question 1: Harmonic Mean

Implement harmonic_mean, which returns the harmonic mean of two positive numbers x and y. The harmonic mean of 2 numbers is 2 divided by the sum of the reciprocals of the numbers. (The reciprocal of x is 1/x.)

def harmonic_mean(x, y):
    """Return the harmonic mean of x and y.

    >>> harmonic_mean(2, 6)
    3.0
    >>> harmonic_mean(1, 1)
    1.0
    >>> harmonic_mean(2.5, 7.5)
    3.75
    >>> harmonic_mean(4, 12)
    6.0
    """
    return 2/(1/x+1/y)

Use OK to test your code:

python3 ok -q harmonic_mean --local

Question 2: Speed Converter

Define speed_converter, which takes a value "miles per minute" with units miles per minute and returns the same value converted to kilometers per day.

The approach for converting from miles per minute to kilometers per day is twofold:

  1. Convert Minutes to Days (Hint: Multiply by Minutes / Hour, Hours / Day)
  2. Convert Miles to Kilometers (Hint: Assume 1 Mile = 1.609 Kilometers)

Try to use only a single expression for the body of the function.

def speed_converter(miles_per_min):
    """
    >>> speed_converter(0)
    0.0
    >>> speed_converter(0.5)
    1158.48
    >>> speed_converter(0.75)
    1737.72
    >>> speed_converter(2)
    4633.92
    """
    kilos_per_day = (miles_per_min*1.609)*60*24
    return kilos_per_day

Use OK to test your code:

python3 ok -q speed_converter --local

Question 3: Two of three

Write a function that takes three positive numbers and returns the sum of the squares of the two largest numbers. Use only a single expression for the body of the function.

def two_of_three(a, b, c):
    """Return x*x + y*y, where x and y are the two largest members of the
    positive numbers a, b, and c.

    >>> two_of_three(1, 2, 3)
    13
    >>> two_of_three(5, 3, 1)
    34
    >>> two_of_three(10, 2, 8)
    164
    >>> two_of_three(5, 5, 5)
    50
    """
    return (a*a + b*b + c*c) - min(a*a, b*b, c*c)

Use OK to test your code:

python3 ok -q two_of_three --local

We use the fact that if a>b and b>0, then square(a)>square(b). So, we can take the max of the sum of squares of all pairs. The max function can take an arbitrary number of arguments.

Question 4: Largest factor

Write a function that takes an integer n greater than 1 and returns the largest integer smaller than n that evenly divides n*n-1.

Hint: To check if b evenly divides a, you can use the expression a % b == 0, which can be read as, "the remainder of dividing a by b is 0." However, it is possible to solve this problem without any if or while statements.

def largest_factor(n):
    """Return the largest factor of n*n-1 that is smaller than n.

    >>> largest_factor(4) # n*n-1 is 15; factors are 1, 3, 5, 15
    3
    >>> largest_factor(9) # n*n-1 is 80; factors are 1, 2, 4, 5, 8, 10, ...
    8
    """
    return n - 1

Use OK to test your code:

python3 ok -q largest_factor --local

n*n-1 is equal to (n-1) * (n+1), so n-1 always evenly divides n*n-1.

Question 5: Law of Sines

Write a function that determines whether the Law of Sines is upheld.

In trigonometry, the Law of Sines relates the length of the sides of a triangle with the sines of its angles. In other words, assuming a triangle has three sides of length 'a', 'b', and 'c' in addition to three angles denoted as 'A', 'B', and 'C', the Law of Sines is expressed as follows:

sin(A) / a = sin(B) / b = sin(C) / c

from math import sin

def law_of_sines(a, b, c, A, B, C):
    """
    >>> law_of_sines(1, 1, 1, 1.0472, 1.0472, 1.0472)
    True
    >>> law_of_sines(1, 2, 3, 1, 2, 3)
    False
    """
    is_triangle = math.sin(A)/a == math.sin(B)/b == math.sin(C)/c
    return is_triangle

Use OK to test your code:

python3 ok -q law_of_sines --local

In this function, you are given 6 parameters.

  1. 'a', 'b', and 'c' correspond to the lengths of the triangle's sides.
  2. 'A', 'B', and 'C' correspond to the angles of the triangle in radians.

The 'sin' function has been imported and provided for this problem.