CSC153, Class 5: Conditionals
Overview:
* An algorithm: Turning numeric grades into letter grades.
* Key idea: The conditional.
* Conditionals in Scheme
* Boolean expressions
Administrivia:
* Alternative whiteboard
+ More legible, permanent record
+ Less spontaneous
* Comments on Web site design (other than broken links?)
* Extended office hours now include 9:00-9:50 MTuWF.
* Thursday, 4:30, Sam talks about summer opportunities in CS
+ Warning: Hiring of first-years is gendered
* Due: Writeup 1.
* Assigned: Read Boolean values (which should have been due today).
----------------------------------------
Problem: Sam assigns numeric grades throughout the semester.
Sam eventually compute a "total numeric grade". Grinnell asks
Sam to give letter grades.
Write an algorithm that converts numeric grades to letter grades.
Table for Sam's grading rubric
94-100 A
90-93 A-
---
87-89 B+
84-87 B
80-83 B-
77-79 C+
70-77 C
55-69 D
---
0-54 F
If total-numeric-grade is between 94 and 100 inclusive, give
the student an A.
If total-numeric-grade is between 90 and 93 inclusive, give
the student an A-.
If total-numeric-grade is less-than-or-equal-to 89, give the
student an F.
Subroutine: "between inclusive"
X is between Y and Z inclusive iff
X >= Y and X <= Z.
Potential problems if implemented on the computer ...
* Really good students who have grades greater than 100.
+ Replace the "between 94 and 100" with "greater than or
equal to 94".
+ Make it a requirement that the grade be between 0 and 100.
* Really bad students who have grades less than 0 are covered.
* How do we represent letter grades?
+ As strings
* Fractional grades (e.g., 93.5)
+ Precondition: Whole numbers
+ Convert fractional grades to whole numbers
- By rounding
- ceiling
+ Convert ranges
grade >= 94 and grade <= 100 : A
grade >= 90 and grade < 94: A-
...
Potential issues in writing the algorithm ...
Key algorithm design issue: "Making choices"
----------------------------------------
In Scheme, two key "making choice" control structures
(if ____ ________ _________)
TEST TRUE-EXP FALSE-EXP
Meaning:
Evaluate the TEST.
If the test is false, evaluate the FALSE-EXP and return
its value.
If the test is not false, evaluate the TRUE-EXP and
return its value
Interesting things:
(1) Looks like a normal Scheme expression.
(2) Not evaluated like a normal Scheme expression.
Normal Scheme expressions you evaluate all the arguments
and then apply the procedure.
If evaluates the test first and then decides what to
evaluate next.
(3) "not false" is true
----------------------------------------
Using if to write numeric->letter
; Pre: grade is in [0..100]
; Pre: grade is an integer.
(define numeric->letter
(lambda (numeric)
(if (and (>= numeric 94) (<= numeric 100))
"A"
(if (and (>= numeric 90) (<= numeric 93))
"A-"
"F"))))
Three variants of the first test
* (if (>= numeric 94)
+ Looks nicer
+ Less coding
+ Simpler, and clearer (provided preconditions are met)
* (if (and (>= numeric 94) (<= numeric 100))
+ More specific
+ Closer to specification
+ Enforces precondition
* (if (<= 94 numeric 100)
+ A nice compromise
----------------------------------------
When you have lots and lots of tests, you can use the cond
(cond
(test1 exp1)
(test2 exp2)
(test3 exp3)
...
(testn expn)
(else default))
* Evaluate test1. If it is not false, evaluate exp1 and
use its result (and stop).
* Otherwise, evaluate test2. If it is not false, evaluate
exp2 and use its result (and stop).
* ...
* Otherwise, evaluate testn. If it is not false, evaluate
expn and use its result (and stop).
* Otherwise, evaluate defalut and use its result.
(cond
((<= 94 numeric 100) "A")
((<= 90 numeric 93) "A-")
((<= 87 numeric 89) "B+")
(else "F"))
Alternative
(cond
((>= numeric 94) "A")
((>= numeric 90) "A-")
((>= numeric 87) "B+")
(else "F"))
----------------------------------------
Can you solve this problem without if or cond? (Using only
the Scheme you know right now?)
How about a variant:
numeric is a whole number
numeric is between 0 and 10, inclusive
10: A
9: A-
8: B+
7: B
6: B-
5: C+
4: C
3: D
2: F
1: F
0: F
Key idea (thanks Oge): Make a list and use list-ref.
(define grades
(list "F" "F" "F" "D" "C" "C+" "B-" "B" "B+" "A-" "A"))
(define numeric->letter
(lambda (numeric)
(list-ref grades numeric)))
----------------------------------------
Here's what we ended up writing in DrScheme.
(define make-list
(lambda (count val)
(vector->list (make-vector count val))))
(define grades
(append
(make-list 55 "F")
(make-list 15 "D")
(make-list 7 "C")
(make-list 3 "C+")
(make-list 4 "B-")
(make-list 3 "B")
(make-list 3 "B+")
(make-list 4 "A-")
(make-list 7 "A")))
(define numeric->letter
(lambda (numeric)
(list-ref grades (ceiling numeric))))
----------------------------------------
What can the tests look like?
* Arithmetic comparison (=, <=, <, >, >=)
* Combine expressions: and, or, not
* Type predicates: number? symbol? string? list? null?
* Other kinds of equality testing
+ = compare numbers
+ eq? compares memory location associated with a value
+ eqv? compares symbolic values (and memory locations)
+ equal? most general, even compares elements of lists
* Ones you define yourself