Sunday, September 15, 2013

Learn to Program: The Fundamentals - Assignment 1

Preface

Requirements

You need to use Python 3 for this assignment. Python 2 is not suitable.

A1 Problem Domain: Coordinated Universal Time

The problem domain for this assignment involves time zones, and in particular Coordinated Universal Time (UTC), which is "the primary time standard by which the world regulates clocks and time" [Wikipedia]. As you know, there are many different time zones in the world. Wikipedia has a nice map of the time zones.
As of this writing, there are 40 time zones. One of them, UTC+00:00, is considered to be in the "middle" of the other time zones. All time zones have names, such as UTC+02:00, that indicate the number of hours and minutes they are away from UTC+00:00. For example, the Philippines are in time zone UTC+08:00 because clocks there are set 8 hours later than in time zone UTC+00:00. If it's noon in time zone UTC+00:00, it's 20:00 in time zone UTC+08:00.

Representing hours, minutes, and seconds using a float

In this assignment, we are sometimes going to represent hours and minutes and seconds together as a float. 1 hour will be represented as 1.0, 1 hour and 30 minutes as 1.5, and so on.

Preconditions

Some of the functions you will write assume that parameter values are in a certain range. The technical term for these restrictions is precondition: in order for the function to work, the precondition must be met. A precondition is a warning to whoever calls the function that the function was designed to work only under those conditions. When you see a precondition, that means we are guaranteeing that we will only call that function with values that meet the precondition. You can assume that the parameter values meet the preconditions, you do not need to check them. The preconditions are there to make your lives easier!

Floating-point numbers in this handout

This assignment involves float calculations, and as you know, these can be inexact. As an example, here is code copied from the Python shell:
>>> 7 / 3000
0.0023333333333333335
>>> 7 * (1 / 3000)
0.002333333333333333
Because we leave it up to you to write some expressions, your functions may return values that are very slightly different from the examples in our docstrings. As long as they are very close, your code will be marked as correct; you don't need to make your code match our expected results exactly.

Print statements: don't use them

Nothing in the assignment requires print statements; your code will be marked as incorrect if you use them.

What to do

There are several functions that you will need to implement. We have listed the functions roughly in order of complexity. Each function body will be quite short.



Step 2: Complete the code for function seconds_difference

Function name:
(Parameter types) -> Return type
Description
seconds_difference:
(number, number) -> number
The parameters are times in seconds. Return how many seconds later the second time is than the first. Please note: in a1.py, we have provided the completed docstring for this function, including example function calls with the expected return values.

def seconds_difference(time_1, time_2):
    """ (float, float) -> float

    Return the number of seconds later that a time in seconds
    time_2 is than a time in seconds time_1.
       
    >>> seconds_difference(1800.0, 3600.0)
    1800.0
    >>> seconds_difference(3600.0, 1800.0)
    -1800.0
    >>> seconds_difference(1800.0, 2160.0)
    360.0
    >>> seconds_difference(1800.0, 1800.0)
    0.0
    """
    return time_2 - time_1

 

Step 3: Complete the code for function hours_difference

Here is some helpful information:
  • there are 60 seconds in 1 minute
  • there are 60 minutes in 1 hour
Function name:
(Parameter types) -> Return type
Description
hours_difference:
(number, number) -> float
The parameters are times in seconds. Return how many hours later the second time is than the first. (Please note: in a1.py, we have provided the completed docstring for this function, including example function calls with the expected return values.)

def hours_difference(time_1, time_2):
    """ (float, float) -> float

    Return the number of hours later that a time in seconds
    time_2 is than a time in seconds time_1.
       
    >>> hours_difference(1800.0, 3600.0)
    0.5
    >>> hours_difference(3600.0, 1800.0)
    -0.5
    >>> hours_difference(1800.0, 2160.0)
    0.1
    >>> hours_difference(1800.0, 1800.0)
    0.0
    """
   return seconds_difference(time_1, time_2) / 3600

Step 4: Complete the code for function to_float_hours

Function name:
(Parameter types) -> Return type
Description
to_float_hours:
(int, int, int) -> float
The first parameter is a number of hours, the second parameter is a time in minutes (between 0 and 59, inclusive), and the third parameter is a time in seconds (between 0 and 59, inclusive). Return the combined time as a float value. (Please note: in a1.py, we have provided the completed docstring for this function, including example function calls with the expected return values.)

def to_float_hours(hours, minutes, seconds):
    """ (int, int, int) -> float

    Return the total number of hours in the specified number
    of hours, minutes, and seconds.

    Precondition: 0 <= minutes < 60  and  0 <= seconds < 60

    >>> to_float_hours(0, 15, 0)
    0.25
    >>> to_float_hours(2, 45, 9)
    2.7525
    >>> to_float_hours(1, 0, 36)
    1.01
    """
    return hours + minutes / 60 + seconds / 3600

Step 5: Write functions get_hours, get_minutes and get_seconds

Read this section and make sure you understand all of it before you proceed.
We have not provided starter code for these three functions, although we have described them fully in the table below. Follow the Function Design Recipe as you develop these functions in a1.py.
The three functions, get_hours, get_minutes and get_seconds, are related: they are used to determine the hours part, minutes part and seconds part of a time in seconds.
For example:
    >>> get_hours(3800)
    1
    >>> get_minutes(3800)
    3
    >>> get_seconds(3800)
    20
            
In other words, if 3800 seconds have elapsed since midnight, it is currently 01:03:20 (hh:mm:ss).
Here is an overview of how we determined what the example function calls should return:
  • There are 60 seconds in 1 minute and 60 minutes in 1 hour, so there are 60 * 60, or 3600, seconds in 1 hour.
  • Because there are 3600 seconds in an hour, there is 1 full hour in 3800 seconds. There are 200 seconds remaining.
  • Because there are 60 seconds in a minute, there are 3 full minutes in 200 seconds. There are 20 seconds remaining.
  • Therefore 3800 seconds is equivalent to 1 hour, 3 minutes and 20 seconds.
There are several ways to write these three function bodies. You may find operators % and // to be helpful. Function to_24_hour_clock in the starter code has an example of using %.
As an example of the approach you might use, lets assume your program is given a number and you want to work out the "units" portion (remember, the hundred, tens, units thing for decimal numbers?) Let's assume the number is 123.
First, we get rid of the hundreds column:
>>> 123 % 100
23
You can see that 100 goes in to 123 once and leaves us with 23.
Next, we get rid of the tens.
>>> 23 % 10
3
The number 10 divides in to 23 twice and leaves us with 3 and we have achieved our goal; there are 3 "units".
Function name:
(Parameter types) -> Return type
Description
get_hours:
(int) -> int
The parameter is a number of seconds since midnight. Return the number of hours that have elapsed since midnight, as seen on a 24-hour clock. (You should call to_24_hour_clock to convert the number of full hours to a time on a 24 hour clock. This means that the return value should be in the range 0 to 23, inclusive.)
get_minutes:
(int) -> int
The parameter is a number of seconds since midnight. Return the number of minutes that have elapsed since midnight as seen on a clock. (This means that the return value should be in the range 0 to 59, inclusive.)
get_seconds:
(int) -> int
The parameter is a number of seconds since midnight. Return the number of seconds that have elapsed since midnight as seen on a clock. (This means that the return value should be in the range 0 to 59, inclusive.)

 

def to_24_hour_clock(hours):
    """ (number) -> number

    hours is a number of hours since midnight. Return the
    hour as seen on a 24-hour clock.

    Precondition: hours >= 0

    >>> to_24_hour_clock(24)
    0
    >>> to_24_hour_clock(48)
    0
    >>> to_24_hour_clock(25)
    1
    >>> to_24_hour_clock(4)
    4
    >>> to_24_hour_clock(28.5)
    4.5
    """

    return hours % 24

### Write your get_hours function definition here:

def get_hours(sec_since_midnight):
    '''(int) -> int

    Return the number of get_hours that have elapsed since midnight, as seen on a 24-hour clock.

    >>> get_hours(3800)
    1
    >>> get_hours (3600)
    1
    >>> get_hours (9000)
    2
    '''
    return sec_since_midnight // 3600

### Write your get_minutes function definition here:

def get_minutes(sec_since_midnight):
    '''(int) -> int
   
    Return the number of get_minutes that have elapsed since midnight as seen on a clock.

    >>> get_minutes(3800)
    3
    >>> get_minutes(3600)
    0
    >>> get_minutes(900)
    15
    '''

    return (sec_since_midnight - get_hours(sec_since_midnight) * 3600) // 60

### Write your get_seconds function definition here:
def get_seconds(sec_since_midnight):
   
    '''(int) -> int

    The parameter is a number of seconds since midnight. Return
    the number of get_seconds that have elapsed since midnight as
    seen on    a clock.

    >>> get_seconds(3800)
    20
    >>> get_seconds(3600)
    0
    >>> get_seconds(912)
    12
    '''

return sec_since_midnight - get_hours(sec_since_midnight)*3600 - get_minutes (sec_since_midnight)*60

Step 6: Complete functions time_to_utc and time_from_utc

Complete functions time_to_utc and time_from_utc. The header and docstrings are in the starter code. Use those examples to determine the appropriate formula. We have intentionally left out tests involving time zones that are not on the hour: you should make sure you handle those cases.
Function name:
(Parameter types) -> Return type
Description
time_to_utc:
(number, float) -> float
The first parameter is a UTC offset specifying a time zone and the second parameter is a time in that time zone. Return the equivalent UTC+0 time. Be sure to call to_24_hour_clock to convert the time to a time on a 24 hour clock before returning.
time_from_utc:
(number, float) -> float
The first parameter is a UTC offset specifying a time zone and the second parameter is a time in time zone UTC+0. Return the equivalent time in the time zone specified by utc_offset. Be sure to call to_24_hour_clock to convert the time to a time on a 24 hour clock before returning.

def time_to_utc(utc_offset, time):
    """ (number, float) -> float

    Return time at UTC+0, where utc_offset is the number of hours away from
    UTC+0.

    >>> time_to_utc(+0, 12.0)
    12.0
    >>> time_to_utc(+1, 12.0)
    11.0
    >>> time_to_utc(-1, 12.0)
    13.0
    >>> time_to_utc(-11, 18.0)
    5.0
    >>> time_to_utc(-1, 0.0)
    1.0
    >>> time_to_utc(-1, 23.0)
    0.0
    """

    return (time - utc_offset) % 24
   

   

def time_from_utc(utc_offset, time):
    """ (number, float) -> float

    Return UTC time in time zone utc_offset.

    >>> time_from_utc(+0, 12.0)
    12.0
    >>> time_from_utc(+1, 12.0)
    13.0
    >>> time_from_utc(-1, 12.0)
    11.0
    >>> time_from_utc(+6, 6.0)
    12.0
    >>> time_from_utc(-7, 6.0)
    23.0
    >>> time_from_utc(-1, 0.0)
    23.0
    >>> time_from_utc(-1, 23.0)
    22.0
    >>> time_from_utc(+1, 23.0)
    0.0
    """

    return (time + utc_offset) % 24