Functional Problem Solving (CSC 151 2014F) : Labs
Primary: [Front Door] [Schedule] - [Academic Honesty] [Disabilities] [Email] - [FAQ] [Teaching & Learning] [Grading] [Rubric] - [Calendar]
Current: [Assignment] [EBoard] [Lab] [Outline] [Reading]
Sections: [Assignments] [EBoards] [Examples] [Handouts] [Labs] [Outlines] [Readings]
Reference: [Setup] [VM] [Errors] - [Functions A-Z] [Functions By Topic] - [Racket] [Scheme Report (R5RS)] [R6RS] [TSPL4]
Related Courses: [Davis (2013F)] [Rebelsky (2014S)] [Weinman (2014F)]
Misc: [Submit Questions] - [SamR] [Glimmer Labs] [CS@Grinnell] [Grinnell] - [Issue Tracker (Course)]
Summary: We explore some of the kinds of numbers and procedures that many implementations of Scheme, including Racket, support.
a. Determine what type DrRacket gives for the
square root of two, computed by (sqrt 2)
. Is it exact
or inexact? Real? Rational? An integer?
b. How do we know that the answer it gives us is correct? (What does “correct” mean when the answer is irrational?) We could check by squaring the value, as in
>
(* (sqrt 2) (sqrt 2))
Better yet, we could subtract that result from 2, as in
>
(- 2 (* (sqrt 2) (sqrt 2)))
c. What do the results of these experiments suggest? Why do you think you got the answer you got?
d. Do you expect to have the same problem as in the previous exercise if you compute the square root of 4 rather than the square root of 2? Why or why not?
e. Check your answer experimentally.
Suppose that we've defined val
as a number,
lower
as 0, and upper
as 100.
Consider the following definition.
> (define bounded-val (min (max val lower) upper))
a. Suppose val
is 25. What value will this definition associate with
bounded-val
?
b. Suppose val
is 211. What value will this definition associate with
bounded-val
?
c. Suppose val
is -25. What value will this definition associate with
bounded-val
?
d. Explain, in your own words, what the definition computes when
lower
is 0 and upper
is 100.
e. Suppose we redefined lower
to -10 and upper
to 10 and then redid each of a-c. What results would we get?
f. Explain, in your own words, what this definition computes in terms
of lower
and upper
.
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 3 8)
>
(modulo 8 8)
>
(modulo 9 8)
>
(modulo 16 8)
>
(modulo 827 8)
>
(modulo 0 8)
>
(modulo -8 8)
>
(modulo -7 8)
>
(modulo -9 8)
>
(modulo -1 8)
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.
DrRacket's implementation of Scheme permits you to treat any real number as a rational number, which means we can get the numerator and denominator of any real number. Let's explore what numerator and denominator that implementation uses for a variety of values.
a. Determine the numerator and denominator of the rational representation of the square root of 2.
b. Determine the numerator and denominator of the rational representation of 1.5.
c. Determine the numerator and denominator of the rational representation of 1.2.
d. Determine the numerator and denominator of 6/5.
If you are puzzled by some of the later answers, you may want to read the notes on this problem.
Many programming languages have limits on the size of the numbers they represent. In some cases, if the number is large enough, they approximate it. In other cases, if the number is large enough, the calculations you do with the error are erroneous. (You'll learn why in a subsequent course.) And in still others, the language treats large enough values as the special value “infinity”.
See what happens if you try to have DrRacket compute with some very
large exact integers. You may find the expt
function
helpful. Then see what happens if you try convert those integers to
inexact values. Here are two examples to start with, but you should try
more.
>
(define x (expt 2 100))
>
(define ex (exact->inexact x))
See what happens if you try to have DrRacket compute with some very small exact rational numbers (say, 1 divided by one of those large numbers). Then see what happens if you convert those rational numbers to inexact values.
It feels that with integers, rationals, reals, exact, and inexact numbers, Scheme provides more kinds of numbers than you would ever need. But, believe it or not, it provides even more.
What value do you think Racket will give for (sqrt -4)
?
Check your answer experimentally.
Although you may have been told at one time that “negative numbers don't have square roots”, that's only true if we restrict ourselves to real roots. As you've just discovered, Racket supports “complex numbers”, which have not only a real component, but also an imaginary component represented by i, the square root of negative 1. Complex numbers have many uses, including representing points on the plane. We may revisit them later this semester. For now, we're just introducing them to help you understand the depth of Scheme (and to warn you that you will sometimes get answers when you expect errors.
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.
Suppose we have a value, val
. Write instructions that
give val rounded to the nearest hundredth.
For example,
>
(define val 22.71256)
>
(your-instructions val)
22.71
>
(define val 10.7561)
>
(your-instructions val)
10.76
In a problem above, you wrote instructions for rounding a real number to two digits after the decimal place. While such rounding is useful, it is even more useful to be able to round to an arbitrary number of digits after the decimal point.
Suppose precision
is a non-negative integer and
val
is a real value. Write instructions for rounding
val
to use only precision
digits after the decimal point.
>
(your-instructions ... val ... precision ...)
As you write your instructions, you
may find the
function useful.
expt
(expt b p)
computes bp.
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.2.) 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.
The underlying scheme implementation seems to represent the fractional part of many numbers as the ratio of some number and 4503599627370496, which happens to be 252. (Most computers like powers of 2.) By using a large denominator, it helps ensure that representations are as accurate as possible.
If you are energetic, you might scour the Web to find out why they use an exponent of 52.