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