# Welcome to DS2000 CS Practicum 2!

- Recap and clarifications of last week
- Intro to todays excercises
- Taking user input
- Parsing user input
- Unit conversions
- More math operations
- Additional exercise

## Recap and clarifications of last week

Before we get to today's excercise, let's clarify three things that you found confusing last week.

0. Reminder on how to get started:

- On Windows, open the menu in the lower right corner and just type IDLE.
- On Mac, press Cmd + space and type IDLE
- Once shell is open, select File > New File to open a new file and start coding

1. **Shell** and **Editor**. Look at the image below and compare it to what you see on your screen.

Remember to save the contents of the editor window, not the interpreter window!

2. Error messages displayed in shell. The image below will help you read and understand the error messages you see in the shell.

Do you see what the error is?

3. Error images displayed in the editor. The image below will help you read and understand the error messages you see in the editor.

The editor highlights the place where it ran into a problem. You will notice that it sometimes highlights a seemingly wrong place in the code: there's nothing wrong with my call to the function main()! If you're confused, remember that the error is always before the highlight, either in the same line or the line above.
Do you see where the error in this code is?

## The actual practicum of today

Today we're going to practice:

- taking user input
- conversion between different units using the mathematical operations you learnt during the previous practicum (and a few new ones);
- breaking a bigger problem down into smaller, more manageble parts;
- implementing these small parts using functions to make the code more readable;

Specifically, we will implement conversion between units that describe amount of data, time, and data transfer speeds. At the end of the exercise we will have the code that can answer questions like: how long would it take to save an episode of a Netflix series for offline watching over home WiFi? How much would it cost to listen to an album on Spotify while roaming abroad?

I marked the graded parts with a

## Taking user input

We ask the user for data using the`input`

**function**, with the prompt as an

**argument**, for example try running this code in the interpreter:

fav_show = input('What is your favorite show? ')The user's response is now stored in a

**variable**called

`fav_show`

.
You can print it out on the screen using the `print`

function with the `fav_show`

**variable**as the argument:

print(fav_show)You can also add your text or other variables to print in the same line and separate them with commas, like this:

print('Too bad', fav_show, 'is so underrated!')Note that there are no apostrophes around

`fav_show`

when we pass it as an argument, unlike with the words 'Too bad'. Do you understand why? What happens when you run `print('fav_show')`

? Why doesn't it print the name of the show you typed in?
### Excercise 1.1

Use the `main()`

function template to write a program that:

- asks the user for the title of the series they want to watch and the number of episodes.
- prints out the input variables in a readable way (i.e. not just as two values one after another but as a sentence about how many episodes of which series they will save for offline viewing).

''' DS2000 Spring 2019 PR02 - bits and bytes ''' def main(): # ask the user about the title # ask the user about the number of episodes # print main()

Save your answer as `pr02_ex11.py`

, it will be a part of your today's submission.

## Parsing user input

In python everything that the user enters is treated as text. If we expect a number, we must explicitely tell Python to treat the input as one. We can use`float`

for this if we expect a fraction or `int`

if we expect an integer. Run these two pieces of code and see how the output differs.
### Multiplying a string

string = input('Give me an integer: ') print('Your number times ten is: ', 10 * string)

### Multiplying a number

string = input('Give me an integer: ') number = int(string) print('Your number times ten is: ', 10 * number)

### Excercise 1.2

Save your `pr02_ex11.py`

file as `pr02_ex12.py`

. Now you have two identical files with different names. Modify the contents of `pr02_ex12.py`

for this excercise.

Let's assume that one episode of the series is 1.5 GB (one gigabyte) of data. Let's extend the function from the previous excercise to estimate how much data in total the user will need to download. Now your function:

- asks the user for the title of the series they want to watch and the number of episodes
**converts the number of episodes input to a number****calculates the total amount of data and saves it to**`total_data`

**variable**- prints out the input variables in a readable way
**prints out the total amount of data in GB.**

Save your answer as `pr02_ex12.py`

, it will be a part of your today's submission.

## Unit conversion and functions

Great, now we know how much data in**gigabytes**we will need to transfer. Internet connection speeds are expressed in

**megabits per second, Mbps**. To answer how long it will take to download all this data, we have to first convert gigabytes to megabytes to megabits. Have a look at this:

- The smallest amount of data is 1 bit, and the symbol for a bit is a lower case
**b**. - 1 byte is 8 bits. The symbol for a byte is a capital
**B**. - 1 kilobyte is 1000 bytes, the symbol for a kilobyte is
**kB**. - 1 megabyte (
**MB**) is 1000 kilobytes. - 1 gigabyte (
**GB**) is 1000 megabytes.

*Side story, 1 kilobyte was not always 1000 bytes, it used to be 1024 bytes instead. If you have extra time try googling and wrapping your head around the explanation...*.

After defining it, we can run it by typing its name and providing the input argument, for example:

>>> def giga2mega(giga): mega = giga * 1000 return mega >>> giga2mega(1): 1000 >>> giga2mega(1.5): 1500.0

If we want to use it in the `main()`

function (and we do!) we need to 'call' it and save it's output to a variable, like this:

def giga2mega(giga): mega = giga * 1000 return mega def main(): amount_of_data_GB = float(input('How many gigabytes do you want to tranfer?')) amount_of_data_MB = giga2mega(amount_of_data_GB) print("That's", amount_of_data_MB, "megabytes!")

### Excercise 1.3

Take the file from excercise 1.2 and save it as `pr02_ex13.py`

. In the `pr02_ex13.py`

file add the definition of our `giga2mega`

function and a the `bytes2bits`

function you need to write yourself (it's has the same structure as `giga2mega`

but the variable names and the conversion calculation will be different. Then, extend your `main()`

function so now it:

- asks the user for the title of the series they want to watch and the number of episodes
- converts the number of episodes input to a number
- calculates the total amount of data and saves it to
`total_data`

variable **uses**`giga2mega`

to calculate the size of`total_data`

in megabytes and prints it out.**use the caculated size in megabytes and the**`bytes2bits`

function to calculate and print out the size of`total_data`

in megabits- prints out the input variables in a readable way
- prints out the total amount of data in GB.

''' DS2000 Spring 2019 PR02 - bits and bytes ''' def giga2mega(giga): mega = giga * 1000 return mega def bytes2bits(byte): # your code goes here (two lines) def main(): # your code from excercise 1.2 with the requested extensions goes here main()

Save your answer as `pr02_ex13.py`

, it will be a part of your today's submission.

As a last step, we combine the outputs of our two functions to convert gigabytes to megabits like this:

def gigabytes2megabits(gigabytes): megabytes = giga2mega(gigabytes) # converting the input in gigabytes to megabytes megabits = bytes2bits(megabytes) # converting the calculated number of megabytes to megabits return megabits

### Excercise 1.4

Take the file from excercise 1.3 and save it as `pr02_ex14.py`

. From now on, edit file `pr02_ex14.py`

.

A function can take more than one argument. Write a function `estimate_transfer_time`

that takes the amount of data to transfer in gigabytes and the connection speed in megabits per second and calculates the time in seconds necessary to download that amount of data. Extend your main function, so now it:

- asks the user for the title of the series they want to watch and the number of episodes.
**asks the user for their internet speed in Mbps**- converts the number of episodes input to a number
- calculates the total amount of data and saves it to
`total_data`

variable - prints out the input variables in a readable way (i.e. not just as two numbers one ofter another but a nice sentence about how many episodes of which series they will save for offline viewing).
- prints out the total amount of data in GB.
**calculates and prints out the time in seconds necessary to transfer this amount of data on the specified connection**

*Note 1: so far we have been printing out user input by passing it as an argument to the print function. Here, we will pass it as an argument to the functions we wrote ourselves.*

*Note 2: If you're not sure what kind of speeds are reasonable: Internet providers in Boston offer speeds between 50 and 1000 Mbps, but in general your WiFi is not faster than 300 Mbps.*

Your `pr02_ex14.py`

should look something like:

''' DS2000 Spring 2019 PR02 - bits and bytes ''' def giga2mega(giga): mega = giga * 1000 return mega def bytes2bits(byte): # your code goes here (two lines) def gigabytes2megabits(gigabytes): megabytes = giga2mega(gigabytes) # converting the input in gigabytes to megabytes megabits = bytes2bits(megabytes) # converting the calculated numbers of megabytes to megabits return megabits def estimate_transfer_time(gigabytes, speed): # in this line convert gigabytes to megabits # in this line calculate time (in seconds) needed for transfer: # speed is how many megabits can we transfer in one second. # return the time estimate def main(): # your code from excercise 1.2 plus the requested extensions go here main()

Save your answer as `pr02_ex14.py`

, it will be a part of your today's submission.

Test case: use your code to calculate how long it would take to download 4 seasons of 13 episodes (52 episodes total, each 1.5 GB) on a 6 Mbps connection. Expected output: `104000`

. If your output is different, test each function one after another and try to find which one introduces the error.

## A reminder on math operations

Last week we covered addition `+`

, subtraction `-`

, multiplication `*`

, division `/`

, full division `//`

, and modulo (remainder) `%`

.

Python has a **library** called `math`

that will allow us to do more operations than these. To start using it, we need to **import** it. By convention, the import statements are placed on top of the file under the top comment, for example:

''' DS2000 Spring 2019 PR02 - bits and bytes ''' import math def main(): ... main()

This library implements plenty of operations, for example:

- squre root of
`x`

:`math.sqrt(4)`

=2.0 - base-10 logarithm:
`math.log10(100)`

=2.0 - rounding down (to the next lower integer):
`math.floor(4.9)`

= 4.0 - rounding up (to the next higher integer):
`math.ceil(4.9)`

= 5.0

### Excercise 1.5

Take the file from excercise 1.4 and save it as `pr02_ex15.py`

. From now on, edit file `pr02_ex15.py`

Our function so far outputs the transfer time estimate in seconds - it's technically correct but might be difficult for a human to understand (how long is 104000.0 seconds?!). Write a function `format_time(seconds)`

that takes in the number of seconds, rounds them up to the next full integer and then prints it in a human understandable format ("D days, H hours, M minutes, S seconds").
> Show hint

`math`

library in the beginning of your file. Then extend the function you developed previously, so that it:
- asks the user for the title of the series they want to watch and the number of episodes.
- asks the user for their internet speed in Mbps
- converts the number of episodes input to a number
- calculates the total amount of data and saves it to
`total_data`

variable - prints out the input variables in a readable way (i.e. not just as two numbers one ofter another but a nice sentence about how many episodes of which series they will save for offline viewing).
- prints out the total amount of data in GB.
- calculates and prints out the time in seconds necessary to transfer this amount of data on the specified connection
**prints out the time in a human readable format. Remember to print using integers, for example "50 minute(s), 10 second(s)", rather than "50.0 minute(s), 10.0 second(s)".**

Test case: use your code to calculate how long it would take to download 4 seasons of 13 episodes (52 episodes total) on a 2 Mbps connection. Expected output: `3 days, 14 hours, 40 minutes, and seconds`

. If your output is different, but your previous excercise worked, there's probably something wrong with the conversion.

Save your answer as `pr02_ex15.py`

, it will be a part of your today's submission.

## Excercise 2 (optional, but highly recommended)

Ex 2.1: Standard quality Spotify music streams at at bitrate of 160 kbps. Google Project Fi charges $10 per gigabyte. Write the code to answer the question: given the length of an album in hours and minutes, how much does it cost to stream it on Google Fi?

Ex 2.2: Mobile providers have different ways of calculating the cost of transmissions: some charge for each started KB, others for each started MB, and others for each started GB. Let's stick to the Google Fi rate of $10 per gigabyte. It corresponds to $0.01 per megabyte and $0.00001 per kilobyte. Extend the function from Ex 2.1 to report the three variants of cost that depend on the billing (hint: 600.1 MB gets charged as 1GB in GB-based billing, ast 601MB in MB based billing, and 600100 KB in KB based billing.

Save your answer as `pr02_ex2.py`

, it's not mandatory, but it's good for you to know how to do it and good for me to know that you do.