In this homework you will have the chance to familiarize yourself with the Racket programming language. Racket is considered a very "clean" language, with a minimal syntax: few punctuation and formatting rules. In fact some might argue it's too minimal! As a result, Racket is one of the best examples of a language whose focus is supporting computation itself, as opposed to intricate data structuring. In the first problem of this assignment you'll work through Racket's "Quick start" tutorial; in the second problem, you'll implement some mathematical functions in Racket, remind yourself about recursion, and reflect on a few running times... .
For this assignment, you will write (and test!) your Racket code in two files:
To log in to the submission site, use your login id, which you can look-up here. Use the default password at first. After you log in the first time, change it to something you'll remember.
You may submit your work multiple times -- only the file submitted latest will be graded, but all of them will be saved in case you or we need to access them for any reason. The submission site is a convenient way to access your latest copy of a HW assignment if you work on multiple computers.
Design and formatting account for roughly a quarter of the credit for each function or program you complete. Correctness, supported by careful testing of your code, accounts for the rest.
Design, here, means algorithm design, that is, how you break a problem down into smaller pieces and then compose those pieces into an overall solution. Large, convoluted functions are difficult to understand (and debug!). Use small, clear functions with lots of small helper functions, as necessary. Formatting includes coding style: clean and clear structure, meaningful variable and function names, ample use of spacing, and indenting that reflects code structure.
Here are specific formatting features the graders will look for:
As for commenting, in each assignment we ask you to include
Computation in the form of software is useful only to the extent that it works. But it only works (for sure) to the extent that it has been tested! Testing your own software thoroughly is important -- we use test cases to check how well your functions work, and you will certainly want to do the same!
It's impossible to programmatically guarantee that your code is correct. In fact, it's provably impossible to make such a guarantee! In practice, however, creating and running a set of tests for each of your functions, called unit-testing, is vital to producing useful, maintainable software. Unit testing is also a standard industry practice. In particular,
We will use Piazza for all Q&A in the class. You can ask questions that anyone in the class can answer, or (if you need to include code in your question) you can post a private question that only the Profs and Grutors will see.
Sign in to Piazza and check it out. If you have a question - post a question! If you can answer a question - answer a question!
Get to the Dr. Racket programming environment, either by downloading it to your personal computer or by using the CS lab.
On the CS department's Macs in BkB102 and BkB105, Dr. Racket can be found in the Additional Applications folder:
Once you have Racket running, go to the "Quick introduction" site:
The Racket quick-introduction site
which is a fun guide through a small piece of the language that uses images.
What to do Work your way through those examples, at least up to section 8.
Do NOT worry if things start seeming crazy as you get into the later sections -- or, perhaps, the whole time! This problem is to start getting used to learning new computational interfaces, and they always seem crazy at first! You won't learn everything at once, but start to keep a list of some questions you have about the Racket language.
We will examine the ideas in sections 6-8 in more detail next week. As for sections 9-11, they are Racket-specific, rather than CS-specific, and we won't use enough Racket in CS 60 to warrant worrying about those.
Do type (or copy) the functions from sections 4-6 into the definitions pane of Dr. Racket's interface. Run them as you go. Also, save those definitions as the file hw0pr1.rkt. This is the file you will submit for problem 1.
To complete this problem, add these two functions and your answer to Question #1 to your hw0pr1.rkt file.
Make a list of at least three notes about Racket. These can include:
Using the provided checkerboard function as a guide, create a function
named cboard. But cboard should take three inputs, so that
its definition will begin
The inputs should be n, the number of pixels of the component square
of the resulting checkerboard, color1, a string representing the
color of the upper left square, and color2, a string representing
the color of the lower right square. The output should be an 8x8 checkerboard,
using only squares of the designated size, with the appropriate colors.
A good strategy for this problem is to understand the Racket quick-indtroduction
tutorial's checkerboard
function and then write an appropriately altered version named cboard.
(define (cboard n color1 color2)
Here is a screenshot of four examples:
Be sure to have a header comment for your function!
Also, if you'd to add features, consider
trying the extra credit, below...!
Write another function, named hcomb, whose definition will begin
where the inputs are the same as for cboard, except that there
is an additional color. Then hcomb should create a nine-by-nine
grid of three-by-three patches of filled-in circles of the appropriate
colors and the appropriate size. Start from
the existing functions and change things slowly!
You will want to use (disk diameter): click on
the circle link in the quickstart tutorial
to see all of the graphical primitives available.
(define (hcomb n color1 color2 color3)
Here are two examples (Bears and Packers colors, perhaps...):
Again, add a header comment for your function... .
As completely optional extra-credit (of up to +5 points each), create functions named alien and/or extra that composes Racket's graphics primitives into artistic images of your own.
The alien function should output a picture of an alien, broadly interpreted, and should take one input: (alien input) - you may choose what input does, e.g., it can control size, color, or some other feature such as number of eyes... .
You have almost complete leeway in designing extra, e.g., it can create abstract, geometrical pictures or even more elaborate representations of aliens. It has only two constraints:
Be sure to submit your hw0pr1.rkt at the submission site without including your name!
For this problem, you will want to start with this starter file
hw0pr2.rkt
which includes a few examples of Racket syntax and its
testing interface, along with the functions we wrote in
class this week.
As with human languages, lots of examples are the most
efficient way to start feeling comfortable with
a new programming language!
This problem asks you to write a number of mathematical functions.
For each problem below, you should include at least one additional test in your file, beyond what we provide. In this assignment we will provide complicated test cases. Before you write code, you should write out some simple test cases (because complicated test cases aren't very helpful for initial debugging).
Please be sure these additional tests are clearly
marked with a comment above them. For example, for the erdos
function you might have in your code:
; provided tests
(check-expect (erdos 84) 42)
(check-expect (erdos 85) 256)
; additional tests
(check-expect (erdos 6) 3)
(check-expect (erdos 7) 22)
For this problem define a function, named erdos,
with one argument, N. Thus, your definition might
begin as follows:
;; erdos: the "3N+1 function"
;; inputs: an integer, N
;; output: 3N+1, if N is odd
;; N/2, if N is even
(define (erdos N)
This function should compute the following:

Here are a couple of tests to try.
Remember that you need (generate-report) at the end of your file in
order for Racket to print a summary of your tests' results.
; provided tests
(check-expect (erdos 84) 42)
(check-expect (erdos 85) 256)
Warning: Racket's built-in integer-division function is
quotient, not the / symbol. If you try (/ 3 2) you will
get the rational number three-halfs (three-halves?),
instead of the floating-point number 1.5
or the integer 1. But (quotient 3 2) evaluates to 1, as expected with
integer division. The "mod" function in Racket is modulo, so that (modulo 12 7)
evaluates to 5. See Prof. Keller's
Racket Reference
Card for a listing of the most important library functions.
Write erdos-count, a function of one positive integer argument:
(define (erdos-count N)where erdos-count should return the smallest number of times erdos must be iterated, when started with an input of N, in order to arrive at a value of 1. Let's use the symbol ==> to mean "evaluates to." Then, (erdos-count 3) ==> 7, because
(erdos (erdos (erdos (erdos (erdos (erdos (erdos 3))))))) ==> 1and there are 7 applications of erdos above.
Here are a few Racket tests:
; provided tests
(check-expect (erdos-count 26) 10)
(check-expect (erdos-count 27) 111)
These are relatively complicated test cases. BEFORE writing code
you should write out 2-3 exceptionally simple test cases, which will
be helpful fo debugging. Here's one you might consider including:
(check-expect (erdos-count 1) 0)
Be sure to use recursion when writing erdos-count. As a starting point, consider how we wrote half-count in class.
Write count1bits, a function of one nonnegative integer argument:
(define (count1bits N)where count1bits should return the number of times the bit 1 appears in the binary representation of N. Remember that N will be a nonnegative integer. Feel free to review binary representation, if you have not seen it for a while - you might also try the tests below, by hand.
Here are a few Racket tests (you should write a few simpler test cases before writing your code):
Hints: you do not need to actually convert N to
binary. (In fact, don't.) Instead, consider if the input is odd -
what does that say about its rightmost bit?
What if it's even? Also, what arithmetic operation will "get rid of" that rightmost bit,
thereby "shifting" all the bits to the right by one place?
As with all things Racket, recursion will be key!
; provided tests
(check-expect (count1bits 6) 2)
(check-expect (count1bits 7) 3)
(check-expect (count1bits 42) 3)
Write power, a function of two integer inputs (it's OK to presume non-negative integers):
(define (power b p)where b is the base and p is the power: it should evaluate to bp. We also specify that, for this function, b0 should be 1 for any b. Note that using the built-in power function expt is not allowed here -- imagine you're implementing it for the Racket library... . Rather, you should implement power in terms of multiplication, addition/subtraction, and recursion using the formula bp = b*bp-1. If you know a fancier algorithm for computing powers, save it until the next problem!
Here are a few Racket tests (you should write a few simpler test cases before writing your code):
The factorial example from class is a good starting point.
; provided tests
(check-expect (power 2 5) 32)
(check-expect (power 5 2) 25)
Experimental Run-time
Run the timing command:
(time (power 1 N))
replacing N by 1000, 10000, 100000, and 1 million.
In fact, you're welcome to use the built-in expt for this:
;; time trials
(time (power 1 (expt 10 3))) ;; 1^1000
(time (power 1 (expt 10 4)))
(time (power 1 (expt 10 5)))
(time (power 1 (expt 10 6))) ;; 1^1000000
In a clearly marked comment, report your results. Multi-line comments in
Racket use #| at the start and |# at the end.
The numbers returned by time are
Write fast-power, identical in its inputs and outputs to power:
(define (fast-power b p)where b is the base and p is the power. This time, however, you should use the following idea:
Warning! Just writing fast-power
using the above technique will not necessarily make it fast!
In particular, you'll need to be sure you don't repeat
computation too much. One helpful construct in Racket is
let, which is used for defining local variables. (You
saw let in the graphics examples of problem 1.)
Here is an example:
Here, the function f computes (x+1)*(x+1), but
only does the work of adding 1 once.
Look over let in the Racket documentation
or the reference sheet (or use this example as a guide)
in order to see if you can get
your fast-power to actually run fast!
(And it does run really fast!)
(define (f x)
(let* (
(y (+ x 1))
)
(* y y)))
Experimental Run-time In a comment in your code, run timing tests for fast-power that are analogous to the above tests for power, report the results for fast-power. You might see how big an exponent you can raise 1 to before things start slowing down... .
The test values will be the same as for power:
; provided tests
(check-expect (fast-power 2 5) 32)
(check-expect (fast-power 5 2) 25)
For completely optional extra credit of up to +5 points each, write two functions: first-factor and factor, each of which take one integer input, N, which will be greater than 1.
(define (first-factor N)
(define (factor N)These should compute the smallest ("first") factor of N and a list of all the factors of N, respectively. (See the tests.) Note that these add several challenges! First, you'll need to use Racket's lists (there are lots of references in its documentation). In addition, you'll need helper functions, and you'll need to be creative in what those helper functions will be!
Here are two tests for each:
Note that factor's output should include the 1
at the front of its list. As with the previous problems, you should include
at least one test of your own to earn full (extra) credit for these.
; provided tests
(check-expect (first-factor 41) 41)
(check-expect (first-factor 42) 2)
(check-expect (factor 41) '(1 41))
(check-expect (factor 42) '(1 2 3 6 7 14 21 42))
Be sure to submit both hw0pr1.rkt and hw0pr2.rkt at the submission site!