Published using Google Docs
HW1 - Style and Recursion in Racket - CS60
Updated automatically every 5 minutes

CS 60 – HW1

Homework 1: Recursion Practice and Racket & Java Style

We will ease into CS60 for this homework by practicing writing recursive code in Racket. In the process, you will have the opportunity to work on your fluency with Racket and practice the professional skills of testing, tracing, debugging, and documentation. It takes time to build the skills needed to learn new languages with ease and confidence, so remember that you have Piazza and fabulous grutors to help out when you have questions!

You will notice that, in CS 60, our homework assignments can be somewhat… verbose. We know that detailed descriptions can sometimes be a bit overwhelming. However, we think that you will find the extra detail to be helpful as you work through the content at your own speed. Get after it and have fun!

You are welcome (and encouraged) to buddy or pair program for all parts of this assignment! (The syllabus can remind you of the differences.) If you have not tried buddy or pair programming, give it a try! Feel free to use the “Search for Teammates” channel on Piazza to identify potential programming buddies, or ask the teaching team to help you find a partner during lab hours.

We are really excited to help people on Piazza - so please ask questions early and often! Some more tips:

- Your profs & the awesome CS60 Grutoring team


Problem 0: Getting Started

Problem 1: Style in Racket

Problem 2: Recursion in Racket - erdos

Problem 3: Recursion in Racket - count1bits

Problem 4: Recursion in Racket - power

Problem 5: Conditionals, Booleans, and Math in Java

Rubric

Elements of Racket style:

Elements of Java style:


Problem 0: Getting Started

Make sure you are added to Piazza and Gradescope using your official school email address.

Piazza: Find Resources and Ask Questions

We will use Piazza to distribute course material and for all Q&A in the class. You can ask questions that anyone in the class can answer. You can even post anonymously if you prefer! If you need to include code you have written, you can also post private questions so that only the instructors (professors and grutors) can see. Have a question already? Great; post it! See a question you can answer? Help a fellow student!

Gradescope: Submit your Work

This assignment (and everything for CS 60) will be submitted on Gradescope. We try to limit implicit bias by grading anonymously in CS 60, so be sure your submissions never include any information that might identify you.

The Honor Code, Pair Programming, and Collaboration

Please read the syllabus carefully if you have not already.

Organizing our Files

Clone the CS60 Git repository containing all of the starter files for this class.

With the advent of search utilities, it is all too easy to put files anywhere on our computer and then search for them as needed. But it turns out that your operating system has a structure in which files are organized into folders (aka directories), and folders can be nested inside other folders. We strongly strongly recommend that you create a folder specifically for CS 60, then subfolders for different components of CS 60.

Why is organization important? We have seen from experience that poor file organization often results in duplicate copies of the same file. Maybe you downloaded starter code in one place, then edited and saved it somewhere else. Then you accidentally submit the starter code version rather than the one you edited. Oops!

Feel free to use whatever folder structure makes sense to you. Here is one recommendation: Have a top-level folder on your desktop (or elsewhere) named “CS60”. Inside this folder, have a folder for “Week1”, and inside “Week1”, have a folder “Weekly1” that stores any notes or practice code from the weekly, and a folder “HW1” that stores any code from the homework.

Problem 1: Style in Racket

Remember to check the CS 60 Convention and Style Guide!

There are many important aspects of style to consider when writing code. For example:

At this point, we expect that you have had some practice in CS 5 writing good, concise comments:

But code style is more than just comments. Good style should also:

Because these three elements of good style may be less familiar to you, we would like to provide a one-time only opportunity to earn points for writing code with terrible style! For this question, we would like you to:

  1. Pick two of the above: {formatting, meaningful names, and avoiding redundancy}.
  2. For each of your choices:
  1. Pick one of your examples. Improve it so that it now demonstrates good style!

http://ranzey.com/generators/bart/index.html

We hope you have fun with this and really come up with something spectacularly confusing/bad/terrible! You will submit your bad style examples, explanations of badness, and improvements.


Problem 2: Recursion in Racket - erdos

Note that there are two Gradescope assignments labeled HW #1.2. One is for just your Erdos implementation file and the other one is just for your test cases file.

Examine the starter files, and follow along with the problem description.

This problem explores the erdos function. erdos takes in one argument, a positive integer N, and computes the following:

In the starter file erdos.rkt, notice how the function has a top-level comment that matches this description:

;; erdos: the "erdos" function
;;   input: a positive integer, N
;;   output: 3N+1, if N is odd
;;           N/2, if N is even

(
define (erdos N)
    ...)

The erdos-count function takes in one argument, a positive integer N, and computes the smallest number of times erdos must be applied, starting with an input of N, to arrive at a value of 1.

Let us use the symbol ==> to mean “evaluates to.” Then, (erdos-count 3) ==> 7 because it takes 7 applications of erdos to reach 1:

(erdos (erdos (erdos (erdos (erdos (erdos (erdos 3))))))) ==> 1,

Or thinking recursively, (erdos-count 3) is 7, because (erdos 3) is 10 and it takes 6 more applications of erdos to get from 10 to 1.

The starter file erdos_tests.rkt includes some provided test cases for each function. You can choose to work through these cases to help you understand the intended functionality. (If a test case seems too complex to work through by hand, then you can go ahead and skip working through it manually, i.e. use it only to test your code.)

Tips as you work through this problem:

Part A: Write function comments and test cases

Why do we write tests first? To ensure we understand what a function is supposed to do before we try to implement it! Writing tests first is so important there is even a name for it in software development: test-driven development.

Things to keep in mind:

; student tests

This comment is provided in the starter file for this problem.

Before you move on, verify that you can run the tests. For now, they will all fail because the function stubs in the starter code return the wrong answers! If you want added security before moving on, submit erdos_tests.rkt on Gradescope. The autograder will run our implementation of erdos and erdos-count against your test cases, which should pass.

Part B: Write erdos

Hints:

Be sure your function passes the provided test cases and your additional test cases.

If you want added security before moving on, submit erdos.rkt on Gradescope. The autograder will run your implementation of erdos against our test cases, which are likely more exhaustive than your set.

Part C: Write erdos-count 

Be sure to use recursion when writing erdos-count. Do not forget that every recursive definition needs at least one base case that does not result in a recursive call!

Here are a few more tests in the starter file:

; provided tests
(check-equal? (erdos-count 26) 10)
(
check-equal? (erdos-count 27) 111)

These are relatively complicated test cases — if the second test fails because your (erdos-count 27) produces 119 instead of 111, you will know there is a bug, but there are so many reasons this complicated computation could have gone wrong that it does not provide any hints for finding and diagnosing the problem.  That is why we asked you to add two super simple test cases in part A, which should be much more helpful for debugging.

For this assignment, you do not have to worry about inputs that are less than 1 (which will likely produce an infinite loop). It would be best practice to add some input checks to return a little error message rather than infinitely looping, but we think the problem is hard enough without worrying about this right now, so we do not require input checking. :-)

If you are having trouble, try using the methods in the weekly to reason about recursion. In particular, we recommend using trace on erdos and/or erdos-count.

Important: Remember to (re)submit your final versions oferdos.rkt and erdos_tests.rkt on Gradescope.

Part D (optional): The Collatz Conjecture

No matter the value of N, will applying erdos always reach 1? Read more about the Collatz Conjecture! (We suggest at least reading the introduction, including the quote by Paul Erdős.)

More fun: Erdős was such a prolific mathematician that academics measure our “distance” to him through the Erdős number. Former HMC President Klawe has an Erdős number of 1!


Problem 3: Recursion in Racket - count1bits

This problem asks you to implement and test the count1bits function, a recursive function that takes in one non-negative integer argument N, and returns the number of times the bit 1 appears in the binary representation of N.

Here is the function signature of count1bits, which tells us the function name and its argument.

(define (count1bits N)

To understand the functionality of count1bits, you might need to review binary representation. (In particular, CS 5 Gold/Black cover base conversions, but CS 5 Green does not.)  If you have not seen it, you might also try the tests below (by hand). Feel free to use the internet to research binary representation; there are a lot of great resources out there!

Here are a few Racket tests, to complement the simpler test cases you will write.

; provided tests
(
check-equal? (count1bits 6) 2)
(
check-equal? (count1bits 7) 3)
(
check-equal? (count1bits 42) 3)

Part A: Prepare your solution files

#lang racket

(require rackunit)
(
require "count1bits.rkt")

(provide count1bits)

Part B: Write function comments and stubs, and test cases (before you write any code!)

If you want added security before moving on, submit count1bits_tests.rkt on Gradescope. The autograder will run our implementation of count1bits against your test cases, which should pass.

Part C: Write count1bits 

Hints:

Optional: Add input checking to gracefully handle unexpected input.

Important: Remember to (re)submit your final versions of count1bits.rkt and count1bits_tests.rkt on Gradescope.


Problem 4: Recursion in Racket - power

power is a recursive function that takes in two non-negative integer arguments base and pow, where pow is the power to raise the number base to. power should evaluate to basepow. Note that base0 should evaluate to 1 for any value of base. fast-power is identical to power (same inputs and outputs), but, as its name implies, just does things faster (details on how later).

Function signatures:

(define (power base pow)

(define (fast-power base pow)

Here are some things to notice about the variable names we chose:

Here are a few Racket tests, to complement the simpler test cases you will write.

; provided tests
(
check-equal? (power 2 10) 1024)
(
check-equal? (power 42 10) 17080198121677824)

You should use these same test cases for fast-power too.

On this problem, using good style may require the most effort! If you would like feedback on your commenting style, please ask a grutor or instructor. See also the detailed rubric of bad style elements.

Part A: Prepare your solution files and write simple test cases

If you want added security before moving on, submit power_tests.rkt on Gradescope. The autograder will run our implementation of power and fast-power against your test cases, which should pass.

Part B: Write power 

The built-in function expt is not allowed here -- imagine you are implementing it for the Racket library. Rather, you should implement power in terms of multiplication, addition/subtraction, and recursion:

(If you know a fancier algorithm for computing powers, please save it until the next problem!)

Part C: Write fast-power

In Problem 1, we discussed how redundant calculations can be a symptom of badly-styled code. Next, we will improve our implementation of power by using an algorithm to reduce redundant calculations.

 

To implement fast-power, use the following idea:

Hints:

Part D (optional): Compare!

We claimed that fast-power is faster than power. Let us see if that is true using Racket’s time function.[1] You do not have to understand the details of the syntax below; in brief, we are calling power and fast-power and telling Racket to ignore printing the output using void. (The actual value of base^pow can be huge for large powers, and printing that value might take longer than computing it!)

(time (power 2 100000) (void))

(time (fast-power 2 100000) (void))

Optional: Add input checking to gracefully handle unexpected input.

Important: Remember to (re)submit your final versions of power.rkt and power_tests.rkt on Gradescope.

Problem 5: Conditionals, Booleans, and Math in Java

Before going any further, please get the Java plug-in of VSCode set up by following the Java VSCode instructions on the class web page. This guide covers everything from installing VSCode to getting the right Java version and uses JavaBasics_starter from the GitHub repository as the example.

Stop by grutoring or office hours if you have questions up to this point!

This problem will familiarize you with the Java programming language – or, at least, its syntax. Later in CS 60, we will consider Java’s object-oriented design and the capabilities that make it a popular industry/enterprise language.

One of CS 60’s goals is to help you feel confident that you can use any new computational language effectively and efficiently – all you need is a syntax reference. This problem practices this skill using problems from CodingBat, which has many small one-function challenges and some succinct references.

We have also included a few problems that use the Java class Math. It has helpful constants like PI and helpful methods that do things such as return the max of two numbers or calculate the absolute value of a number.

Part A: Read how to tackle this problem

Your task is to complete the methods in Basics.java. Here is what you should do for each method:

We ask that you make an earnest try to answer each question on your own. If you need to use the solutions, you are free to do so. But, if you do, please include a comment in your code for that function explaining what facet of the problem you had trouble with.

Example: Imagine we needed to look at CodingBat’s solution for the sleepIn problem. In that case, it is okay to use their solution as long as we include a comment such as the one below.

/**
* I used the CodingBat solution here because I did not know that 
* || means "or" in Java and that ! means "not" in Java.
*/
public static boolean sleepIn(boolean weekday, boolean vacation) {
   
// your implementation here
}

Notice that single-line comments in Java are indicated by //. Multi-line comments in Java are indicated by /* at the start and */ at the end.

Remember, the goal is that you become comfortable with Java and its syntax – articulating what was new or surprising in a comment will help you do just that!

Part B: Write code to pass all the tests

Complete the methods in the file Basics.java to make the tests in BasicsTests.java pass.

We recommend working iteratively. That is, after you complete one function, test it by opening the tests file and clicking on the green “Run” button to run the tests.

Before you submit, be sure to go over the checklist in How to Submit.

Rubric

We want to be as transparent as possible in our grading system.

Problem 1 (12 points): 4 points for each bad style example, 4 points for correction and explanation.

Problems 2-4 (16 points each):

Problems 2 and 3:

Tests (4 points): You write 2 tests. 1 point each for correctness. 1 point each for being good/simple.

Function implementation: (12 points):

1 point for correct recursive approach

3 points for style (15 elements of style below. Minus 0.5 points for each violated to min of 0.)

8 points for autograded functionality

        Problem 4:

                Tests (4 points): You write 2 tests. 1 point each for correctness. 1 point each for being good/simple

                (fast-)power implementation (12):

 3 points for style (15 elements of style below. Minus 0.5 points for each violated to min of 0.)

 1 point for correct recursive approach to power

 2 points for using let or let* correctly in fast-power

 1 point for correct recursive approach to fast-power (calls itself rather than power)

 5 points for autograded functionality

Problem 5: 11 points functionality and 6 points for style

                

Elements of Racket style:

We will check for the following elements of bad style on Problems 2-4:

Elements of Java style:

We will check for the following elements of bad style:

Notable differences from Racket noted in blue!

How to Submit

Let VSCode help!

Do NOT use the autograder as a debugger!


[1] If you are interested in the details, Racket documentation tells us time returns the CPU time, real time, and GC (garbage collection) time, all in milliseconds. For our purposes, we care about CPU time.