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. It has a familiar notation borrowed from Math.

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
2. Evaluate the operands (from left to right).
3. 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

So what is a function anyway?

In math we see functions all the time. Mathematical functions map inputs to transformed outputs. A less obvious role functions serve is to abbreviate. Instead of writing out some complicated polynomial like x^9 + 3x^8 + 4x^4 - 7x^4 + x - 23 every time we'd like to use it, we define f(x) as x^9 + 3x^8 + 4x^4 - 7x^4 + x - 23 once then use it by plugging in numbers (ie. f(5)).

Functions in computer science "function" in a very similar way. When you find yourself about to copy paste code, you should probably be defining a function. Remember converting Fahrenheit to Celsius! We coded that 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``````

## Questions

### 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``

### 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``

### 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``

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``

`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``

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.