Summary: We explore some of the kinds of numbers and procedures that Scheme (well, the implementation of Scheme that MediaScript uses) supports.
As you may recall, the reading on documenting procedures introduced a variety of procedures that compute grades.
The documentation for this procedure, while a bit long, seems quite straightforward.
;;; Procedure: ;;; compute-grade ;;; Parameters: ;;; grade1, a real number ;;; grade2, a real number ;;; grade3, a real number ;;; grade4, a real number ;;; grade5, a real number ;;; grade6, a real number ;;; Purpose: ;;; Compute a weighted average of the six grades, using the ;;; top-secret course grading policy. ;;; Produces: ;;; grade, a number ;;; Preconditions: ;;; All grades must be non-negative. ;;; Postconditions: ;;; grade is no smaller than the smallest of the six grades. ;;; grade is no larger than the largest of the six grades. ;;; grade is non-negative (implied by previous postconditions).
The first implementation, which simply computed the average, looks like this:
(define compute-grade
(lambda (grade1 grade2 grade3 grade4 grade5 grade6)
(/ (+ grade1 grade2 grade3 grade4 grade5 grade6 )
6)))
The second implementation, which dropped the lowest grade and doubled the highest grade, looks like this.
(define compute-grade
(lambda (grade1 grade2 grade3 grade4 grade5 grade6)
(/ (+ grade1 grade2 grade3 grade4 grade5 grade6
(max grade1 grade2 grade3 grade4 grade5 grade6)
(- (min grade1 grade2 grade3 grade4 grade5 grade6)))
6)))
a. Check that the second version of
computes a grade using
the strategy specified in the narrative. (That is, that it drops the
lowest grade and doubles the highest grade.) You might, for example,
use grades of 0, 50, 50, 50, 50, and 80.
compute-grade
b. Write a new version of compute-grade that drops both
the lowest and highest grade.
c. Does this new version correspond to the documentation given in the reading? Why or why not?
d. Suppose someone wrote a new version of compute-grade that
returns the average of the homework assignments, with an additional one
point of extra credit for each assignment over 80. Would this version
correspond to the documentation? Why or why not?
Consider the following procedure.
(define bound
(lambda (val lower upper)
(min (max val lower) upper)))
a. Suppose we always use 0 for lower and
100 for upper. What value do you expect
bound to return when val
is 10? 120? 2386? -42?
b. Check your answers experimentally.
c. Explain why this procedure is called
“bound”.
Consider the following procedure.
(define image-bounded-select-ellipse!
(lambda (image operation left top width height)
(image-select-ellipse! image operation
(bound left 0 (* 0.5 (image-width image)))
(bound top 0 (* 0.5 (image-height image)))
(bound width 20 40)
(bound height 20 40))))
a. Create an image on which you can test
image-bounded-select-ellipse!.
b. Identify at least one set of values (left, top,
width, and height) for which
image-bounded-select-ellipse! behaves the same
as image-select-ellipse!.
c. Identify at least one set of values (left, top,
width, and height) for which
image-bounded-select-ellipse! behaves differently
than image-select-ellipse!.
d. Explain in English what image-bounded-select-ellipse!
does.
As the reading suggests, the modulo procedure
computes a value much like the remainder, except that the result is
always the same sign as the second parameter, called the modulus.
(So, when we use a positive modulus, we get a positive result.)
The reading also suggests that modulo provides
an interesting alternative to using max and
min to limit the values of functions.
a. What value do you expect each of the following to produce?
>(modulo 254 256)>(modulo 256 256)>(modulo 257 256)>(modulo 515 256)>(modulo 2567 256)>(modulo 0 256)>(modulo -256 256)>(modulo -257 256)>(modulo -255 256)>(modulo -1 256)
b. Check your answers experimentally, one at a time. If you find that any of your answers don't match what Scheme does, try to figure out why (asking your professor or a tutor if you need help), and then rethink your remaining answers before checking them experimentally.
As the
reading on numbers suggests, Scheme provides
four functions that convert real numbers to nearby
integers: ,
floor,
ceiling, and
round. The reading also claims
that there are differences between all four.
truncate
To the best of your ability, figure out what each does, and what distinguishes it from the other three. In your tests, you should try both positive and negative numbers, numbers close to integers and numbers far from integers. (Numbers whose fractional part is 0.5 are about as far from an integer as any real number can be.)
Once you have figured out answers, check the notes on this problem.
As you may recall from an earlier exercise, it is sometimes useful to be able to count the value 1 for a high score and a value 0 for a lower score. (For convenience, we'll say that a score of 80 or above is high and a score below 80 is low. We'll also assume that all scores are between 0 and 100.)
Most of us would give the instructions for converting score to count as something like “If the score is 80 or above, the count is 1; otherwise, the count is 0”. However, you have yet to learn to write conditionals (expressions that make choices).
Are you doomed? Certainly not. One of the four functions you've just learned, in conjunction with some other arithmetic operations would allow us to create counts for scores. (Yes, we're being deliberately vague. Part of the goal of this problem is for you to think about approaches.)
a. Write a procedure, ( that, given a grade between 0
and 100, returns 0 if the number is less than 80 and 1 if the grade
is 80 or above. If the grade is not in the range [0..100], this
procedure can do anything. You may return exact or inexact numbers.
For example,
grade-count
grade)
>(grade-count 80)1>(grade-count 79)0>(grade-count 81)1>(grade-count 10)0>(grade-count 95)1>(grade-count 90.5)1.0>(grade-count 60.5)0.0
b. Suppose we also wanted to support grades larger than
100, continuing our policy of “any grade 80 or over gets 1”.
Will your code for part a work? If not, write a new version of
that also works for
numbers greater than 100. T
grade-count
>(grade-count 79)0>(grade-count 80)1>(grade-count 120)1>(grade-count 167)1>(grade-count 2009)1
c. Suppose we also wanted to support negative grades. (Yes,
there are teachers who give negative grades.) Will your code
for part a or part b work? If not, write a new version of
that also works for
negative numbers.
grade-count
You may recall that we have a number of mechanisms for rounding real numbers to integers. But what if we want to round not to an integer, but to only two digits after the decimal point? Scheme does not include a built-in operation for doing that kind of rounding. Nonetheless, it is fairly straightforward.
Write a procedure, ( that rounds round-to-hundredths
r)r
to the nearest hundredth. For example,
>(round-to-hundredths 22.71256)22.71>(round-to-hundredths 10.7561)10.76
As you may have noted, the procedure
image-bounded-select-ellipse! converted an
elliptical selection to one that had to start in the upper-left
quadrant and had both height and width between 20 and 40.
We might use modulo to achieve
similar limits. Here's one attempt.
(define image-strange-select-ellipse!
(lambda (image selection left top width height)
(image-select-ellipse! image selection
(modulo left (quotient (image-width image) 2))
(modulo top (quotient (image-height image) 2))
(+ 20 (modulo (- width 20) 21))
(+ 20 (modulo (- height 20) 21)))))
a. Create a 200x200 image and call it canvas.
b. What differences, if any, do you expect between the following three selection calls:
>(image-select-ellipse! canvas REPLACE 10 10 30 30)>(image-bounded-select-ellipse! canvas REPLACE 10 10 30 30)>(image-strange-select-ellipse! canvas REPLACE 10 10 30 30)
c. Check your answer experimentally.
d. What differences, if any, do you expect between the following three selection calls:
>(image-select-ellipse! canvas REPLACE 100 10 30 30)>(image-bounded-select-ellipse! canvas REPLACE 100 10 30 30)>(image-strange-select-ellipse! canvas REPLACE 100 10 30 30)
e. Check your answer experimentally.
f. What differences, if any, do you expect between the following three selection calls:
>(image-select-ellipse! canvas REPLACE 10 10 60 5)>(image-bounded-select-ellipse! canvas REPLACE 10 10 60 5)>(image-strange-select-ellipse! canvas REPLACE 10 10 60 5)
g. Check your answer experimentally.
In a problem above, you wrote a procedure that rounded a real number to two digits after the decimal place. While such rounding is useful, it is even more useful to let the client of your procedure choose how many digits after the decimal point to use.
a. Write a procedure, (, that
rounds round-to
r places)r to places places
after the decimal point.
As you write , you
may find the round-to useful.
expt(expt b p) computes bp.
b. Try redefining
in terms of round-to-hundredths.
round-to
Here are the ways we tend to think of the four functions:
( finds
the largest integer less than or equal to floor r)r.
Some would phrase this as “floor rounds
down”.
(
finds the smallest integer greater than or equal to
ceiling r)r. Some would phrase this as
“ceiling rounds up”.
(
removes the fractional portion of truncate r)r, the portion
after the decimal point.
( rounds round r)r to the nearest integer.
It rounds up if the decimal portion is greater than 0.5 and it rounds
down if the decimal portion is less than 0.5. If the decimal portion
equals 0.5, it rounds toward the even number.
>(round 1.5)2>(round 2.5)2>(round 7.5)8>(round 8.5)8>(round -1.5)-2>(round -2.5)-2
It's pretty clear that floor and
ceiling differ - If r
has a fractional component, then ( is one less than
floor
r)(.
ceiling r)
It's also pretty clear that round differs from all of them,
since it can round in two different directions.
We can also tell that truncate is different from
ceiling, at least for positive numbers, because
ceiling always rounds up, and
removing the fractional portion of a positive number causes us
to round down.
So, how do truncate and floor
differ? As the previous paragraph implies, they differ for
negative numbers. When
you remove the fractional component of a negative number, you
effectively round up. (After all, -2 is bigger than -2.3.) However,
floor always rounds down.
Why does Scheme include so many ways to convert reals to integers? Because experience suggests that if you leave any of them out, some programmer will need that precise conversion.