Exercise - Making Change

Do you remember physical money? In olden times I used to collect small change in a jar and periodically sort through it so I could do my laundry. I always seemed to have too many of the coins I didn’t need, and to few of the ones I did need! This problem is about making change; it’s also about making functions. To answer it you’ll need two pieces of outside information. First: US coinage consists of pennies ($0.01), nickels ($0.05), dimes ($0.10), quarters ($0.25), and dollar coins ($1.00). Second: UK coinage consists of pence, 2p coins, 5p coins, 10p coins, 20p coins, 50p coins, 1 pound coins, and 2 pound coins.

You’ll also need to use the R operators %/% and %%. These represent integer division and modulo. For example 16 divided by 3 equals 5 with a remainder of 1 so 16 %/% 3 returns 5 while 16 %% 3 returns 1. Before beginning this exercise, experiment with %/% and %% to make sure you understand how they work. If necessary, search the internet to find out more about them or read the R help file “Arithmetic Operators.”

For technical reasons that I won’t delve into here, the simplest reliable way of representing monetary values in a computer is by using whole numbers rather than decimals. Rather than representing fourteen pounds and thirty-two pence as 14.32, for example, we’d store this value as 1432. In short, we store the number of pence (or cents) as an integer. Please follow this convention throughout.

Exercise 1: Fill in the code block.

The following code block outlines a simple algorithm for making change. The customer is owed a certain number of cents, an integer between 1 and 99, and your task is to calculate how many quarters, dimes, nickels, and pennies to remove from the cash register. The rule is to always give as many high denomination coins as you can before moving on to lower denomination coins. If the customer is owed $0.75, for example, you remove three quarters rather than seven dimes and a nickel. Fill in the gaps in the code, run it, and display the resulting vector change. Check the result by hand to make sure your logic is correct.

cents <- 73
quarters <- cents %/% 25
cents <- cents %% 25

dimes <- ______ # Delete the underscores & fill in the gap!
cents <- ______ # ditto! 

nickels <- ______ # ditto!
cents   <- ______ # ditto! 

change <- c('quarters' = quarters,
            'dimes' = dimes,
            'nickels' = nickels,
            'pennies' = cents)

Exercise 2: Define a function for US coins

You’ve written some handy code! But now suppose you wanted to reuse it to make change for a different amount, say $0.37 or $0.19. Copying-and-pasting your existing code is tedious and error prone. Instead of doing this, write a function called make_change_US(). It should take a single input argument cents, a integer between 1 and 99, and return a vector called change listing the number of quarters, dimes, nickels, and pennies formatted as above. Run your function to make change for $0.37 and $0.19 and check the results against your hand calculations.

To solve this, you can edit this code block:

# Define make_change_US().

# In R, you define functions as follows:
function_name <- function(argument) {
  # What the function does goes in here.
  return(result)
}

Exercise 3: Define a function that works for US and UK coins.

The function make_change_US() has some limitations. Suppose we wanted to make change for UK currency rather than US currency. This would require us to write a completely new function despite the underlying logic of the problem being identical. There’s a better way forward. Write a new function called make_change() that it takes two input arguments. The first argument is cents. As before, this is a integer between 1 and 99. The second argument is new: currency is a named vector that stores the denominations between 1 and 99 cents along with their labels. For example we would set currency equal to c('quarter' = 25, 'dime' = 10, 'nickel' = 5, 'penny' = 1) for US currency and c('50p' = 50, '20p' = 20, '10p' = 10, '5p' = 5, '2p' = 2, '1p' = 1) for UK currency. As above, make_change() should return a named vector called change indicating how many of each coin to give as change, but now this vector should take its names from currency. The logic is the same as above, but the implementation is a bit trickier. While there are various ways to solve this, the simplest is probably to use a for loop. Test make_change() by making change for 78 cents/pence in US/UK currency. Compare your results to make_change_US(78) to double-check.

To solve this, you can fill in the code blocks below:

# First, define make_change().

# You might want to use a for loop to implement this. 
# For loops in R work as follows:

for (variable in vector) {
   # Do stuff!
}
# Then, define the US and UK currency arguments that enter make_change().

# Test your function for 78 cents/pence.
# Compare to make_change_US(78) to double-check.

Solutions

Don’t peek at the solution code until you’ve worked through the exercises own your own! It’s easy to convince yourself you understand something when you don’t and working through these exercises on your own will be extremely helpful for one of the upcoming problem sets.

Exercise 1: Fill in the code block.

Show solution code
cents <- 73

quarters <- cents %/% 25
cents <- cents %% 25 # Update cents.

dimes <- cents %/% 10
cents <- cents %% 10

nickels <- cents %/% 5
cents <- cents %% 5

change <- c('quarters' = quarters,
            'dimes' = dimes,
            'nickels' = nickels,
            'pennies' = cents)
change
quarters    dimes  nickels  pennies 
       2        2        0        3 

The change for 73 cents is 2 quarters, 2 dimes, and 3 pennies. This fulfills the requirement of giving out as many high-denomination coins as possible.

Exercise 2: Define a function for US coins.

Show solution code
# Define make_change_US().
make_change_US <- function(cents) {
  
  quarters <- (cents - cents %% 25) / 25 # same as above, but replace the %/% 
  cents <- cents %% 25
  
  dimes <- (cents - cents %% 10) / 10
  cents <- cents %% 10
  
  nickels <- (cents - cents %% 5) / 5  
  cents <- cents %% 5
  
  pennies <- cents
  
  change <- c('quarters' = quarters, 'dimes' = dimes, 'nickels' = nickels,  
              'pennies' = pennies)
  return(change)
}

# Test it for $0,37 and $0.19.
make_change_US(37)
quarters    dimes  nickels  pennies 
       1        1        0        2 
Show solution code
make_change_US(19)
quarters    dimes  nickels  pennies 
       0        1        1        4 

Exercise 3: Define a function that works for US and UK coins.

Show the code
# Define make_change().
make_change <- function(cents, currency) {
  
  change <- rep(NA, length(currency)) # rep() creates a vector of NAs, with as 
                                      # many entries as there are different coins
                                      # in the currency.
  names(change) <- names(currency)    # Name the vector elements.
  
  for(i in 1:length(currency)) {
    # Generalizing make_change_US().
    change[i] <- (cents - cents %% currency[i]) / currency[i] 
    cents <- cents %% currency[i] # Update cents as before.
  }
  
  return(change)
}

# Define the US and UK currency arguments that enter make_change().
US <- c('quarter' = 25, 'dime' = 10, 'nickel' = 5, 'penny' = 1)
UK <- c('50p' = 50, '20p' = 20, '10p' = 10, '5p' = 5, '2p' = 2, '1p' = 1)

# Test for 78 cents/pence.
make_change(78, US)
quarter    dime  nickel   penny 
      3       0       0       3 
Show the code
make_change(78, UK)
50p 20p 10p  5p  2p  1p 
  1   1   0   1   1   1 
Show the code
# Compare to make_change_US(78) to double-check.
make_change_US(78)
quarters    dimes  nickels  pennies 
       3        0        0        3 

Again, the tests for 78 cents/pence show that the function returns the largest possible number of high-denomination coins. make_change_US() and make_change() return the same result.