ulrail.gif

HW J5: Functions

  ur-2c.gif urrail.gif
blrail-nonavbar.gif

Home | Resources | Homeworks | Exams
Lectures | Labs | Contacts | Submit | TAs

br-2a.gif   br-2c.gif brrail.gif
spacer.gif spacer.gif

Purpose

This homework has two purposes. The first purpose of this homework is to help you understand functional abstraction and functional programming.  The second is to show you how to build upon smaller functions to achieve larger functions. 

All of your code should be in a public class Arithmetic, and in a Arithmetic.java file.  We are not providing any skeleton code.  There are five parts to this homework, all of which are described below.

Functional Abstraction

The idea in functional abstraction is to think of programs as computing functions, while ignoring the details of how such functions are programmed. One of the simplest and most important examples is a function that takes one argument of type int and returns a value of type boolean where the return value is true if the given integer value was zero and false otherwise. Remember: abstraction means to ignore details. It is among the most powerful intellectual tools of the programmer. Here's the essence of a program, in Java, that represents this function:

// return true if value==0, and false otherwise
static boolean isZero(int value) {
      // details elided
}

In Java, functions are also called methods.  We will be using both terms in this homework -- remember that they are synonyms!

You can see that we've ignored the details of the program implementation -- meaning you have to fill in the body of the method. The important point is that you've got your self a function!

For this homework, all the methods you program should be included in the Arithmetic class, but OUTSIDE the main() method.  All methods need to be declared static.  We will get into what static means in a future lecture.

Of course someone has to fill in the details at some point (i.e. how the isZero() method works); but for now you can act as if you've got the desired function. For example, you now know everything that you need to know about how this function behaves to write the following code in your main() method:

if (isZero(3)) {
      System.out.println("Zero!");
} else {
      System.out.println("Non-zero!");
}

What we've done is to simplify our lives as programmers by separating two fundamental concerns: (1) specifying a function, and representing that specification in a programming language, here Java, and (2) providing the detailed implementation. All we need in order to write code that uses the function is the specification. Of course for that code to operate fully as intended we do need an implementation. In the real world of computer program design, figuring out what specifications to write is by far the most important and difficult part of the program. Developing good implementations, while challenging and interesting, is a much easier task.

The specification is an abstract representation of the function. It allows us to reason about and to use the function without having to study the details of its implementation. That's what we mean by functional abstraction. We think about and organize programs as functions, while separating specification and implementation issues. In that way, we divide the challenge of program design up into separate sub-problems: the problem of (a) deciding what functions we need, which we document in the form of specifications, and (b) deciding how to implement these functions, which we do by writing code.

First Task

At this point, you should implement the isZero() function and write a main() routine to test it (i.e. more than the code snippet above for the testing part).  Remember that all of your code should be in a public class Arithmetic, and in a Arithmetic.java file.  See below for an example of such a main() method. 

Building Upon Functions

A second major idea in the area of functional abstraction and functional programming is the idea that we can build bigger and more complex functions out of small, simpler ones! This strategy gives us another way to manage the otherwise overwhelming complexity of computer program design: we decompose (break up) large programs into smaller parts. In particular, big functions are implemented by using the specifications of simpler functions: namely by using function call as a program composition (building up) mechanism.

To teach you the amazing power of functional abstraction and functional programming, we will show you that most of arithmetic can be composed from just three very simple functions: isZero(), increment and decrement, along with the notions of function call and iteration. We've already given you the specification of isZero(). Here are specifications of increment() and decrement().

// increment takes an integer value and returns that integer value plus one.
static int increment(int value) {
      // details
}

// decrement takes an integer value and returns that integer value minus one.
static int decrement(int value) {
      // details
}

Second Task

You should implement these simple functions and write more in your main() method to test them.  Again, these methods should be declared in the Arithmetic class, and need to be static.  Remember that, in Java, you need to return the new value -- any modification to the parameter will be forgotten about when the method finishes.

Third Task

Great! You've now got a basis for implementing an amazing variety of more complex, and more interesting, arithmetic functions. Here's the next part of your homework on the topic of functional abstraction and functional programming. Implement each of the following function specifications using only the functions you've previously implemented and the programming mechanisms of sequential composition (i.e. one statement after another), alternation (if statements), iteration (loops), and function call.  In other words, you can use variables, for and while loops (and thus operators such as ++i in your for loop), etc., but you need to build these methods from increment(), decrement(), and isZero().

// return a plus b
int plus(int a, int b) {
    if ( b >= 0 ) {
        while (!Arithmetic.isZero(b)){
            a = Arithmetic.increment(a);
            b = Arithmetic.decrement(b);
        }
    } else {
        while (!Arithmetic.isZero(b)){
            a = Arithmetic.decrement(a);
            b = Arithmetic.increment(b);
        }
    }
    return a;
}

// return a times b
int times(int a, int b) {
      // implement arithmetic multiplication of a and b using only plus() along
      // with sequential composition, alternation and iteration
}

// return a exp b
int exp(int a, int b) {
      // implement exponentiation, returning a ^ b, using only times along with
      // sequential composition, alternation and iteration
      // Note that if b < 0, then this method should return 0
}

Note that the plus() method is provided for you.  Also note how it will handle negative values as well as positive values.  times() must also handle negative values, but get it working with positive values first!  If the second value of exp() is negative, your method can just return 0.

Just copying the plus() method body into times, and trying to tinker with it to get it working will not work.  You need to understand what is going on in the plus() method, and then understand how one would (in English) do a times() method before you can write the code for the times() method.

What we see is that we can build up the familiar arithmetic operations by the iterated application of simpler functions, "bottoming out" at increment(), decrement(), and isZero().  Note that you can use any method you define for successive methods -- for example, you can use plus() in minus().  If you follow the pattern one more step, iterating the application of exp(), what function do you get?

Fourth Task

Now implement minus(), integer divide(), and modulus()!  As with the above methods, you can use loops, comparisons, etc., as long as the value you build up uses plus(), increment(), etc.  For the divide() method, if the second value is zero, you can just return 0.  These method must also handle negative numbers.

Fifth Task

You should write a main() method that tests all of the methods you have implemented.  Your program must not ask for any input!  You should pick values that sufficiently test your methods.  Thus, just testing isZero() with one value is not a sufficient test -- it should be tested with a zero value, and one or more non-zero values.  Your code should print out the results from the test (i.e. what was expected, and what result was obtained from the method calls).  Because your main() method tests all of your methods, you do not need to include an execution run as comments.  However, all of the other good programming practices from HW J1 need to be in this homework as well.

To give you an idea of what we are looking for, below is the beginning of a main() method that tests the method developed in this homework.  You are welcome to use what is below, but you will obviously have to add more code to the main() method to test the other parts of this homework.  You need to supply sufficient tests to ensure that your methods work properly.  Does exp() return 1 when the second parameter is 0?  Does exp() return 0 when the second parameter is negative?

public static void main(String []args){

	// Tests of isZero()
	System.out.println ("isZero() tests");
	System.out.println("Is 0 equal to zero? " + Arithmetic.isZero(0));
	System.out.println("Is 1 equal to zero? " + Arithmetic.isZero(1));
	System.out.println("Is -1 equal to zero? " + Arithmetic.isZero(-1));
	System.out.println();

	// Tests of increment()
	System.out.println ("increment() tests");
	for ( int i = -2; i <= 2; i++ )
    	System.out.println("Increment of " + i + " is: " + Arithmetic.increment(i));
	System.out.println();

	// Other tests to be filled in...
}

Where to Start

This homework will be much easier if you work through it one method at a time.  Write the first method, and then sufficiently test it in your main() method.  Then write the second method, and sufficiently test it in your main() method.  This will make the entire homework much easier, and it will take much less time to complete.

Submission

When you are finished, submit the Arithmetic.java file.

spacer.gif
spacer.gif footer-middle.gif spacer.gif