CS303E Homework 5

Instructor: Dr. Bill Young
Due Date: Friday, September 27, 2024 at 11:59pm

Copyright © William D. Young. All rights reserved.

Assignment

Write a program in file GradeStats.py that accepts an arbitrary number of grades (int or float) from the user and prints out some statistics about the series of grades entered: how many grades were entered, the number failing (< 70), the number passing, the average grade, the minimum grade, and the maximum grade. You can assume that all grades entered will be non-negative numbers. Stop accepting grades when the user enters -1. If the user enters a -1 before any grades have been entered, you'll print a special message. Otherwise, you'll print several lines of output. See the Sample Output below. BTW: ints are also floats, so you can treat an int as a float without loss of precision.

Below is some sample output. You should mimic this exactly for the given inputs. Each indented line has two spaces at the beginning. There are two columns of spaces between the colon after "Number of grades:" and the first digit of 100.00. You can assume that the numbers in the summary have width at most 6 spaces.

> python GradeStats.py
Enter a grade or -1 to finish: -1

  No grades entered.

> python GradeStats.py
Enter a grade or -1 to finish: 12.9
Enter a grade or -1 to finish: 67.8942
Enter a grade or -1 to finish: 82
Enter a grade or -1 to finish: 100.0
Enter a grade or -1 to finish: 57
Enter a grade or -1 to finish: 99.9
Enter a grade or -1 to finish: -1

  Number of grades:       6
  Number failing:         3
  Number passing:         3
  Minimum grade:      12.90
  Maximum grade:     100.00
  Average grade:      69.95

>
This homework is primarily designed to give you some practice using loops, but you'll also need some if statements.

Finding the Min and Max: One issue that always confuses students is how to find the minimum and maximum grades entered. They think that you need to store all of the grades and sort them or something like that. That approach would certainly work but it's wasteful of space and totally unnecessary. Also, we haven't yet covered lists in the class, so don't use them. But you don't need them.

Think about this problem as follows. Suppose we're talking and I tell you I'm going to rattle off a bunch of numbers. At the end, I want you to tell me the biggest number I mentioned. I start: "9, 15, 130, 2, 14, 79, 27, ...." Notice that you certainly don't need to remember all of the numbers. At any point, you only need to remember a single number, the biggest one I've mentioned to that point. If you hear a smaller number, you can ignore it. But if you hear a bigger number, then that's the new biggest number so far and you just need to remember that one. Something similar is true for finding the smallest number. Think about the logic and how to implement it.

And BTW: what are the min and max before you start? They are undefined. Some students try setting them initially to very small and very big numbers, but that's dangerous (particularly if the legal inputs are unconstrained; notice we didn't say that 100.00 was the maximum possible grade). If no numbers are entered, you won't need them. If there are, then the min and max are initially equal to the first number entered. Do that instead.

Stopping early: Often you'll want to exit your program early. For example, in this assignment if you find that the user enters -1 immediately, you'll print a message and be done. You can always do that with if statements, but it sometimes makes for a more complicated overall structure. Another way is to put your code into a function, main(). To exit main, you execute a return statement. Note you can't do this unless your code is inside a function. Here's something close to what this might look like:

def main():

    ....
    if grade == -1:
        print("No numbers entered.")
        return
    ...
This is yet another reason to put your code into a main() function. BTW: your function doesn't have to be called main; we'll introduce user-defined functions in the next module.

Turning in the Assignment:

The program should be in a file named GradeStats.py. Submit the file via Canvas before the deadline shown at the top of this page. Submit it to the assignment hw5 under the assignments sections by uploading your Python file.

Your file must compile and run before submission. It must also contain a header with the following format:

# File: GradeStats.py
# Student: 
# UT EID:
# Course Name: CS303E
# 
# Date:
# Description of Program: 

Programming tips

Program incrementally: Don't try to write this entire program all at once. In the first pass, you might just handle the input---read numbers and print them until you encounter -1. This will ensure you can handle looping while reading in grades and know when to stop. (But be sure you're treating the grades as numbers, and not as strings.) Then add computing the counts and sum of numbers; you'll need that for the average. Then add finding the max and min. You'll be done before you know it. Some of you will think: "I don't want to do all those steps; it's easier to just do it all at once." You're wrong!

Using Loops: You usually write a for loop if you know in advance how many times the loop will run and a while loop if you don't. For this problem, you don't know how many times the loop will run (iterations). So you have to figure out the loop test. The trick is to make sure that the loop test makes sense the first time you enter the loop.

For this problem, it seems to make sense to stop when the user input is -1. But that means you must have received an input before you entered the loop. But then you don't want to have an input statement as the first thing in your loop, or you'll be throwing away that first input. You have to process that input before you read another one. Think about where you should put your input statement inside the loop.

Sometimes, it makes sense to write a loop test of True when you don't know how many iterations there will be. But then you run the risk of an infinite loop. You have to test inside the loop body to see if you are ready to exit and break if so. If not, you can always continue to another iteration of the loop. Years ago, I worked on a language called Gypsy in which all loops were like this. The loop statement in Gypsy had no test and the only way to exit a loop was an explicit break statement. That's probably why I often write loops that way.

Indenting: (Note: this section is about code, not program output.) Most Python code involves programming constructs like conditionals, loops and functions that require indenting blocks of code. It's recommended that you follow a standard convention, like 4 extra spaces at each level of indentation. It may be that your editor or IDE makes that easy for you by automatically doing the indenting for you.

But if you do it manually and use a combination of tabs and spaces, it's easy to get it wrong. A tab takes you to the next tab stop on the line, which is set (rather arbitrarily) by your editor. If you combine both tabs and spaces, Python might complain about bad indentation even if it appears that all lines in the block start in the same column. If you're having that problem, try globally substituting all tab characters by some number of spaces (perhaps 8) and see what happens. It will at least show where the indendation issue is.