Computer Science Building, Princeton University


Introduction to CS


1.  A Simple Machine

2.  Java Programming

3.  OOP

    • Using Data Types

    • Creating Data Types

    • Modular Programming

    • Encapsulation

    • Inheritance

4.  Data Structures

5.  A Computing Machine

6.  Building a Computer

7.  Theory of Computation

8.  Systems

9.  Scientific Computation

10.  Perspective


 Lecture Notes

Assignments

FAQ









3.2. CREATING JAVA DATA TYPES


This section under major construction.

Building blocks. Data types are an effective way of organizing our software. All the data that we process on a computer ultimately decompose into individual bits, but writing programs that exclusively process bits would be tiresome indeed. Data types allow us to specify how we will use particular sets of bits, and its methods allow us to specify the operations that we will perform on the data. We write programs that process information derived from mathematical or natural-language descriptions of the world in which we live; accordingly, computing environments need to provide built-in support for the basic building blocks of such descriptions - numbers and characters. In Java, our programs are all built from just a few primitive data types:

In modern programming, we think of the type of the data more in terms of the needs of the program than its underlying representation, primarily in order to make programs portable. Thus, for example, we think of a short as a data type that stores integers betweeen -32,768 and 32,767, instead of as a sequence of 16 bits. Moreover, our concept of an integer includes the operations that we perform on them: addition, multiplication, and so forth.

A variety of data types are built into the Java language and libraries. However, we cannot expect Java to contain every conceivable data type that we might ever wish to use. In principle, we could write all of our programs using only the eight built-in primitive types. Fortunately, Java provides a convenient mechanism, called a class, to build up user defined data types from primitive type. This enables us to build higher level compound data types, assign names to them, and work directly with these these higher level abstractions in our programs. In this section, we describe the primary Java constructs to define new data types.

Bouncing ball.

As a first example, we'll consider a data type that represents a ball that moves in the square with coordinates between -1 and 1, and bounces when it collides with a reflecting boundary wall. Before we implement the Ball data type, we describe a client program to demonstrate how we wish to use it. The constructor allocates memory for one Ball object and initializes its position to (0.5, 0.5) and its velocity to a random value. There are two operations that we can apply to a ball. The method move moves the ball in a straight line according to its current velocity. If the ball collides with a wall, it bounces off according to the laws of physics. The method draw draws the ball using our standard graphics library. The following main routine creates two Ball objects by using new to invoke the constructor. Then it goes in to an infinite loop: update the positions of the balls, and then draw them to the screen. When we execute the program, we see an animation of two bouncing balls.
public static void main(String[] args) {
   StdDraw.create(512, 512);
   StdDraw.setScale(0, 0, 1, 1);
   Ball b1 = new Ball();
   Ball b2 = new Ball();
   while (true) {
      StdDraw.clear();
      b1.move();
      b2.move();
      b1.draw();
      b2.draw();
      StdDraw.pause(10);
   }
}

Now we describe how to create the Ball data type itself. We write a Java class to describe the information that we process and to to define the methods for processing them. The full program is Ball.java. We will describe each step in detail.

Aliasing is when the reference to one object is stored in more than one variable.

Ball a = new Ball();
Ball b = a;
a.move();        // a is updated
b.move();        // a is updated a second time
Aliasing can result in a logical bug if we forget that changing the state of one object will have ramifications on the state of other aliased variables referencing the same object.

Arrays of objects. We can group many user-defined objects together in an array, as we have done many times with integers and strings. The client program Balls.java reads in a command line parameter N, creates N objects of type Ball, stores them in an array, and animates them using our standard graphics library. We need to use new in two places: first to allocate a new array, and then to allocate and initialize each individual Ball element.

Ball balls[] = new Ball[N];
for (int i = 0; i 

Student database.

(Replace with a more serious database, perhaps with US cities and longitudes.) The data type Student.java represents a student in an introductory computer science course. Each student record object is comprised of four instance variables representing the first name, last name, email address, and section number. The first three variables store strings and the last stores an integer. This is an example of a compound object since three of the instance variables store reference to String objects.
public class Student {
    private String first;
    private String last;
    private String email;
    private int    section;

    public Student(String first, String last, String email, int section) {
        this.first   = first;
        this.last    = last;
        this.email   = email;
        this.section = section;
    }

The constructor takes four parameters (three strings and an integer) and initializes the corresponding instance variables. The keyword this is used to refer to the object just created to resolve the ambiguity between the parameter named first and the instance variable named first.

We also add two methods to the Student data type. The method less is useful for sorting a list of students by section. It takes another Student reference b as input and returns true if the section number of the invoking Student reference a is less than that of b; otherwise it returns false. The method toString returns a String representation of the object. In this case, it concatenates the various instance variables, with the section number coming first.

    public boolean less(Student b) {
        Student a = this;
        return a.section 

The toString method is a special method that is automatically invoked whenever you use System.out.println. So, if s is a reference to a Student, then System.out.println(s) calls s.toString and prints the resulting String. If no toString method is provided, then Java makes this method return the memory address where the object is stored.

Complex numbers.

Complex numbers are a useful abstraction to model real world quantities, and were introduced in 1545 by Cardano to find real solutions to the cubic equation x^3 = 3pq + 2q. More significantly, complex numbers arise in systems with sinusoidial oscillations, including eletromagnetics, AC circuits, and waves in quantum mechanics. For example, an electromagnetic field is comprised of an electric component, whose intensity is described by a real number a, and a magnetic component whose intensity is described by a real number b. So, we can think of the intensity of an electromagnetic field as a complex number a + bi. The physics of an electromagnetic field is governed by the rules of complex multiplication on the field intensities. In quantum mechanics, physicists use a complex number to describe the probability that a particle is at a particular point in space (e.g., orbitals in chemistry represent regions with a high probability of containing the electron). The Scroedinger equation employs complex numbers to describe the quantum theory of the atom. Engineers use complex numbers to perform frequency domain analysis of functions, including the Laplace and Fourier transforms. Complex numbers are probably most useful for their indirect applications to the real world, including signal processing, integration of real-valued functions, etc.

Program Complex.java defines a data type for complex numbers. It represents a complex number by explicitly storing the real and the imaginary parts as floating point numbers. It supports the following standard arithmetic operations: add, multiply, absolute value (magnitude), and complex conjugate. It also supports utility operations including initialization and conversion to string representation. As an example, we would like a client program to be able to write code like the following:

public static void main(String[] args) {
    Complex a = new Complex( 5.0, 6.0);      //   5 + 6i
    Complex b = new Complex(-2.0, 3.0);      //  -2 + 3i
    Complex c = b.times(a);                  // -28 + 3i
    System.out.println("c = " + c);
}

Now, we implement the complex data type.

Mandelbrot set.

The Mandelbrot set is a specific set of points in the complex plane with many fascinating properties. The points cannot be described by a single mathematical equation. Instead, to determine whether or not a single complex number c = a + ib is in the Mandelbrot set, we define the following sequence of complex numbers: z0 = c, and zi+1 = (zi)2 + c. If the sequence |zi| does not go to infinity, then c is in the Mandelbrot set; otherwise it is not. If you plot the points in the Mandelbrot set black, and those not in the set white, a strange and wondrous pattern emerges, roughly within the 2.0-by-2.0 box centered at -1/2 + 0i. For a more dramatic picture, we replace the white points with color gradations, depending on the number of iterations needed to discover that the point is not in the set. These colors reveal the striking detail of the terrain just outside the Mandelbrot set. The table below shows the iterates for c = 1 + i (left) and c = -1/2 (right).

Mandelbrot iteration

To plot the Mandelbrot set, we first write a function to determine whether or not the complex number c is in the set. The mathematical definition of the Mandelbrot set is precise, but computationally unappealing, since we would have to perform an infinite number of iterations to determine whether a single point is in the set! We are rescued by the following mathematical fact: if |zi| is ever greater than or equal to 2, then the sequence will surely diverge off to infinity, and the point c is not in the set. There is no simple test that would enable us to conclude that c is surely in the set, but if the number of iterations reaches 256, we will assume that it is. The following code fragment implements this strategy, but instead of returning true or false, it returns the number of iterations (between 0 and 255) until |zi| exceeds 2. Note that we don't need to save the entire sequence of iterates in an array; we can compute the new iterate from the previous one.

public static int mand(Complex c, int ITERS) {
   Complex z = c;
   for (int t = 0; t = 2.0) return t;
      z = z.times(z).plus(c);
   }
   return ITERS - 1;
}

To produce the gray-scale image of the Mandelbrot set, we would need to perform the Mandelbrot calculation at every point in the complex plane. Since we cannot plot an infinite number of points, we restrict attention to a particular rectangular region (read in as command line arguments), and plot a "sample" N-by-N grid of evenly spaced points from the continuum. Large values of N will produce higher resolution images, at the cost of more computation. The client program Mandelbrot.java uses complex numbers to plot a gray scale version of the Mandelbrot set.

Mandelbrot set           Mandelbrot set
-1.5 -1.0 2.0 2.0 0.10259 -0.641 0.0086 0.0086

Chaining. Observe how the Mandelbrot function chains multiple method calls into one statement. The following code fragment replaces z with z*z + c.

z = z.times(z).plus(c);

Chained methods are called form left to right. If we wanted to replace z with z * (z + c), we would use parentheses.

z = z.times(z.plus(c));

Operator overloading. It would be nice if the client program could write code like

z = z * z + c;

where c and z are objects of a user-defined type, but Java does not support operator overloading.

Immutability. Another interesting line of code in the Mandelbrot function is

Complex z = c;

This makes z reference the same value as c. The data type Complex is immutable - once we initialize the instance variables, they never change (since there is no method that would do this). This is an important design principle, and is also a feature of Java's String data type. It means that we can do the assignment statement above without having to worry about inadvertently changing c when we change z. On the other hand, such an assignment statement would be perilous with objects of type Ball, since the method move changes the instance variables of the invoking Ball, instead of returning a new Ball object with the updated coordinates.

Impedance.

Impedance is the generalization of resistance from DC circuits to AC circuits. In an AC circuit, the impedance of a component measures its opposition to the flow of electrons at a given frequency ω. The impedance has two components: the resistance and the reactance. The resistance R of a circuit component measures its opposition to the movement of electrons (friction against motion of electrons) when a given voltage is applied. The reactance X of a circuit component measures its ability to store and release energy as the current and voltage fluctuate (inertia against motion of electrons).

In circuits with resistors only, the current is directly proportional to the voltage. However, with capacitors and inductors, there is a +- 90 degree "phase shift" between the current and voltage. This means that when the voltage wave is at its maximum, the current is 0, and when the current is at its maximum the voltage is 0. To unify the treatment of resistors (R), inductors (L), and capacitors (C) it is convenient to treat the impedance as the complex quantity Z = R + iX. the impedance of an inductor is iwL and the impedance of a capacitor is 1/iwC. To determine the impedance of a sequence of circuit elements in series, we simply add up their individual impedances. Two important quantities in electrical engineering are themagnitude of the impedance and the phase angle. The magnitude is the ratio of the RMS voltage to the RMS current - it equals the magnitude of the complex impedance. The phase angle is the amount by which the voltage leads or lags the current - it is the phase of the complex impedance. Program CircuitRLC.java does a computation involving complex numbers and impedance of circuits with resistors, inductors, and capacitiors in series.

Exercise: RLC circuit in parallel. 1/Z = 1/Z1 + 1/Z2 + ... 1/Zn.

Exercise (for objects): repeat series-parallel network for RLC circuits with impedances instead of resistance

Diffusion of particles in a fluid.

Simulate diffusion of particles in a fluid. See BrownianParticle.java in Section 9.8.

Electric charge.

A charged particle exerts a force on other particles. A proton has a charge of +e and an electron has a charge of -e, where the elementary charge e = 1.60217733E-19 Coulombs. The electric potential at a point (x, y) is the potential energy per unit charge. If we move a charge through from one position to another with a different potential, we must exert an amount of work. The electric potential at a point of radial distance r (in meters) from an isolated point charge qi (measured in Coulombs) is equal to Vi = k qi / r, where k = 8.99E09 N m^2 / C^2 is the electrostatic constant. If there are a group of n point charges, the electric potential at a point is the sum of the potentials of the n individual point charges: V = V1 + ... + Vn To visualize the electric potential, we will create a group of point charges, compute the electric potential at set of points in a grid, and plot each grid point in a different color according to its strength. We accomplish this by creating a data type for point charges. Program Charge.java represents each charged particle by its position (x, y) and its electrical charge (q). The method distanceTo that returns the radial distance between this particle and the location (x, y). The method potential returns the electric potential at (x, y) from this point charage. (Alternatively, could have method forceTo(Charge b). Then the method fieldX(x, y) could be replaced by forceTo with a charged particle located at (x, y) with charge = e.)
public class Charge {
    private static double k = 8.99E09;  // electrostatic constant (N m^2 / C^2)
    private double x, y;                // position of point charge (m)
    private double q;                   // charge (C)

    public Charge(double x, double y, double q) {
        this.x = x;
        this.y = y;
        this.q = q;
    }

    public double potential(double x, double y) {
        return k * q / distanceTo(x, y);            // V = kq / r
    }

    public double distanceTo(double x, double y) {
        double dx = x - this.x;
        double dy = y - this.y;
        return Math.sqrt(dx*dx + dy*dy);
    }
}

The figures below illustrate the electric potential of several randomly positioned particles with charges of equal magnitude. Positive potentials are drawn in shades of red, negative in blue, and neutral in green.

Electric potential      Electric potential

We declare the variable k to be static. This means that k is a variable shared by all instances of the class. By declaring it to be final we promise never to change its value; if we break our promise the Java compiler will complain.

Electric field lines.

Michael Faraday introduced an abstraction called electric field lines to visualize the electric field. By Coulomb's law, the electric field at a point induced by a point charge qi is given by Ei = k qi / r2, and the direction points to qi if qi is negative and away from qi it is negative. If there are a group of n point charges, the electric field at a point is the vector sum of the electric fields induced by the n individual point charges. We can compute it by summing up the components in the x- and y- directions. The figure below illustrates the field lines for two equal positive point charges (left) and two point charges of opposite signs (right). The second configuration is called an electric dipole: the charges cancel each other out, and the electric field weakens very quickly as you move away from the charges. Examples of dipoles can be found in molecules where charge is not evenly distributed. Oscillating dipoles can be used to produce electromagnetic waves to transmit radio and television signals.

Electric potential      Electric potential

Program FieldLines.java draws 10 electric field lines coming out of each charge. (We take some liberties since traditionally the number of field lines per unit area should be proportional to the magnitude of the field strength.) Each line starts on a 1-pixel circle around the charge, at twelve equally spaced angles. The electric field at a point (x, y) from a point charge qi is given by Ei = k qi / r2, where qi is the magnitude of the charge i and r is the radial distance from it. The field due to several charges is the vector sum of the field due to each, and can be found by adding the x- and y-components. After calculating the electric field strength, we move in the direction of the vector field and draws a spot. We repeat this process until we reach the boundary of the region or another point charge. The figures below illustrate the electric potential and field lines for several random charges of equal magnitude.

Electric potential and field lines      Electric potential and field lines

Class variables.

An Instance variables are variables that are associated with each object. Class variables are associated with the class itself, so there is only one shared among all of the objects. To declare a class variable, you preface the declaration with the keyword static. This is convenient when you are declaring constants to be shared across the class. For example, each electric charge uses the same electrostatic constant, so there is no need to define it for each individual charge. Instead, you can define it once, and the same variable will be shared.
private static double k = 8.99E09;  // electrostatic constant (N m^2 / C^2)
In this case, it would be even better to add the keyword final. This signifies that you do not plan to change the constant from its initial value. Any attempt to do so will result in a compile time error.
private final static double k = 8.99E09;

Q + A

Q. Is a constructor really a method?

A. No. Constructors do not have return types (not even void), they always have the same name as the class, and they are not inherited. Methods always have return types (possibly void) and are called by name. However, it is possible to issue a return statement in a constructor. Constructors may also call methods.

Q. What happens if I don't explicitly initialize an instance variable?

A. All instance variables are automatically initialized to default values (0 for number types, false for booleans, and the special value null for objects). In contrast, variables that are declared within methods must be explicitly initialized.

Q. What happens if I don't write a constructor?

A. If no constructor is provided, when you use new the system automatically creates a new object and initializes all instance variables to default values (0 for number types, false for booleans, and null for reference types).

Q. When I declare an object, when do I need to use new?

A. Every time you call new, you get a new instance of the data type, with its own instance variables. If you don't need a new instance, but rather just want a new variable of the given type to reference an existing instance, don't use new. Methods can also return new instances by invoking new, e.g., the plus method with the Complex data type.

Q. Suppose I don't include a method toString. What happens if I try to System.out.println an object of that type?

A. It prints out the memory address of that object. In reality, the integer is actually a unique hash code identifying the object, but in practice the hash code is "typically implemented by converting the internal address of the object into an integer."

Q. Why do Java programmers prefer writing c = a.plus(b) and using methods, as opposed to c = Complex.plus(a, b) and functions.

A. One reason is simply less typing, especially if you have to chain together several methods to form an arithmetic expression.

Q. What does the error message "can't make a static reference to a non-static variable" mean?

A.

public class Test {
    private static int M;                     // class variable
    private int N;                            // instance variable
    public static int getM() { return M; }    // OK
    public static int getN() { return N; }    // ERROR
}

Q. What exactly is null?

A. It is a value of the data type null, much like true and false are values of the type boolean, except that the data type null only has one possible value. However, there is no name for the null type, so you cannot declare a variable of this type. The word null derives from the Latin word nullus, which means not any. Setting a reference object to null means ...

Exercises

  1. Modify Ball.java so that each Ball stores its own Color. Make the default constructor assign each new ball a random color. Name the resulting program ColoredBall.java.
  2. Modify Ball.java so that each Ball stores its diameter. Modify the move so that the ball bounces when it touches the boundary instead of when its center touches the boundary.
  3. Why does the following program create a java.lang.NullPointerException when run?
    public class Mystery {
       private String s;
       public void Mystery()    { s = "hello"; }
       public String toString() { return s;    }
       public static void main(String[] args) {
          Mystery m = new Mystery();
          System.out.println(m);
       }
    }
    

    Answer: the programmer probably intended to make the no argument constructor set the string to hello. However, it has a return type (void) so it is an ordinary instance method instead of a constructor. It just happens to have the same name as the class.

  4. Create a data type BallArray.java that represents an array of balls. Its constructor should take an integer parameter N and create an array of N random balls. Include a method update to update all of the balls and a method draw to draw all of the balls.
  5. What happens when you try to compile and execute the following code fragment?
    Student x;
    System.out.println(x);
    

    Answer: it complains that x may not be initialized, and does not compile.

  6. You want to add a constructor to Complex that takes one real argument and initializes a complex object with that value. You write the following code
    public void Complex(double real) {
        re = real;
        im = 0.0;
    }
    

    Why does the statement Complex c = new Complex(1.0) given a compiler error? Answer: constructors do not have return types, not even void. So the code above is actually a method named Complex not a constructor. Remove the keyword void and it will work. This is a common gotcha.

  7. What happens when you try to compile and execute the following code fragment?
    Student[] students = new Student[10];
    System.out.println(students[5]);
    

    Answer: it compiles and prints out null.

  8. What does the following code fragment print?
    Complex c = new Complex(2.0, 0.0);
    System.out.println(c.mul(c).mul(c).mul(c));
    
  9. Modify the toString method in Complex.java so that it prints 3 - i as 3 - i instead of 3 + -i, and prints 3 as 3 instead of 3 + 0i.
  10. What's wrong with the following code fragment that swaps the Student objects x and y?
    Student swap = new Student();
    swap = x;
    x = y;
    y = swap;
    

    Answer: First, the data type Student does not have a no-argument constructor. If it did, then it would technically be correct, but the new Student() line is unnecessary and wasteful. It allocates memory for a new student object, sets swap equal to that memory address, then immediately sets swap equal to the memory address of x. The allocated memory is no longer accessible. The following version is correct.

    Student swap = x;
    x = y;
    y = swap;
    
  11. Add a method minus(Complex b) to Complex that takes a complex argument b and returns the difference between the invoking object and b.
  12. Add a method divides(Complex b) to Complex that takes a complex argument b and returns the quotient of the invoking object divided by b.
  13. Add a method conjugate() to Complex that returns the complex conjugate of the invoking object.
  14. Write a program RootsOfUnity.java that takes a command line argument N and uses Complex to compute and print out the N Nth roots of unity.
  15. Write a program to read in three real numbers a, b, and c and print out all roots of ax2 + bx + c, including complex ones.
  16. Write a program ColorMandelbrot.java that plots a color version of the Mandelbrot set. Read in a 256-by-3 array of color values from standar input into an array, and then use the ith color if the Mandelbrot function takes i iterations. Use the data file mandel.txt as an example.

    Mandelbrot set           Mandelbrot set
    -1.5 -1.0 2.0 2.0 0.10259 -0.641 0.0086 0.0086
  17. Julia sets. The Julia set for a given complex number c is a set of points related to the Mandelbrot function. Instead of fixing z and varying c, we fix c and vary z. Those points z for which the modified Mandelbrot function stays bounded are in the Julia set; those for which the sequence diverges to infinity are not in the set. All points z of interest lie in the the 4-by-4 box centered at the origin. The Julia set for c is connected if and only if c is in the Mandelbrot set! Write a program ColorJulia.java that takes two command line parameters a and b, and plots a color version of the Julia set for c = a + ib. Read in a 256-by-3 array of color values from standar input into an array, and then use the ith color if the Julia function takes i iterations. Use the data file mandel.txt as an example.

    Julia set           Julia set
    -1.25 0.00 -0.75 0.10
  18. Point3D. Create a data type for points in 3 dimensional space. Include a constructor that takes three real coordinates x, y, and z. Include methods distance, distanceSquared, and distanceL1 for the Euclidean distance, Euclidean distance squared, and the L1-distance.
  19. Vector3 Create a data type for vectors in 3-space. Include methods for dot product, creating a unit vector, norm, add, and substract.
  20. Create a data type PhoneNumber.java that represents a US phone number. The constructor should take three string arguments, the area code (3 decimal digits), the exchange (3 decimal digits) and the extension (4 decimal digits). Include a toString method that prints out phone numbers of the form (800) 867-5309. Include a method so that p.equals(q) returns true if the phone numbers p and q are the same, and false otherwise.
  21. Redo PhoneNumber.java but implement it using three integer fields. Make the constructor take three integer arguments. Comment on the advantages and disadvantages of this approach over the string representation.

    Answer: more efficient with time and memory. More hassle to handle leading 0s correct in constructor and toString method.

  22. Write a program to draw the field lines for a uniform field. Arrange N evenly-spaced particles with charge e in a vertical column, and arrange N particles with charge -e in a vertical column so that each charge on one side is lined up with a corresponding charge on the other side. This simulates the field inside a plane capacitor. What can you say about the resulting electric field? A. Almost uniform.

Creative Exercises

  1. IP addresses. Create a data type for IPv4 (Internet Protocol, version 4) addresses. An IP address is a 32-bit integer.
  2. Dates. Create a data type Date that represents a date. You should be able to create a new Date by specifying the month, day, and year. It should supports methods to compute the number of days between two dates, return the day of the week that a day falls on, etc.
  3. Time bombs. UNIX represents the date with a signed integer measuring the number of seconds since January 1, 1970. Write a client program to calculate when this date will occur. Add a static method add(Date d, int days) to your date data type that returns a new date which is the specified number of days after the date d. Note that there are 86,400 seconds in a day.
  4. Qubits. In quantum computing, a qubit plays the role of a bit. It is a complex number a + bi such that |a + bi| = 1. Once we measure a qubit, it "decides" to be a 1 with probability a2 and a 0 with probability b2. Any subsequent observations will always yield the same value. Implement a data type Qubit that has a constructor Qubit(a, b) and a boolean method observe that returns true or false with the proscribed probabilities.
  5. Biorhythms. A biorhythm is a pseudo-scientific profile of the three natural cycles of your body: physical (23 days), emotional (28 days), and intellectual (31 days). Write a program that takes six command line inputs M, D, Y, m, d, and y where (M, D, Y) is the month (1-12), day (1-31), and year (1900-2100) of your birthday and (m, d, y) is today's month, day, and year. It should then print out your biorhythm on a scale of -1.0 to 1.0 according to the formula: sin (2 π age / cycle length). Use the date data type created in the previous exercise.
  6. Biorhythms. Plot your biorhythm in turtle graphics over a 6 week interval. Identify critical days when your rhythm goes from positive to negative - according to biorhythm theory, this is when you are most prone to accident, instability, and error.
  7. Vectors. Create a data type Vector.java for N-dimensional vectors. Support the following operations: vector addition, vector subtraction, vector product (cross product), dot product (scalar product), Euclidean length, scalar multiplication, unit vector (compute normalized vector). Maybe also equals and parallel.
  8. Euclidean points. Create a data type EuclideanPoint.java that represents a d-dimensional point. Include a method so that p.distanceTo(q) returns the Euclidean distance between points p and q.
  9. Vector fields. Write a data type VectorField for vector fields in two dimensions. A vector field is characterized by two real numbers: its magnitude r and its direction θ (or the component in the x- and y- directions). Vector fields are widely used in Newtonian physics to model various quantities including: velocity, displacement, acceleration, force, torque, momentum, and the electrical field. You should be able to add and subtract vector fields according to the usual rule: to add two vectors, draw the two vectors so that the tail of one begins at the head of the other, and join the ends to make the resultant vector.
  10. Soda machine. Create a data type SodaMachine that has methods insertCoin, getChange, buy, etc.
  11. Months. Write a class Month.java that represents one of the twelve months of the year. It should have fields for the name of the month, the number of days in the month, and the birthstone.

    MONTH DAYS BIRTHSTONE
    January 31 Garnet
    February 28 Amethyst
    March 31 Aquamarine
    April 30 Diamond
    May 31 Emerald
    June 30 Alexandrite
    July 31 Ruby
    August 31 Peridot
    September 30 Sapphires
    October 31 Opal
    November 30 Topaz
    December 31 Blue Zircon


  12. Chaos with Newton's method. The polynomial f(z) = z4 - 1 as 4 roots at 1, -1, i, and -i. We can find the roots using Newton's method over the complex plane: z_k+1 = z_k - f(z_k)/f'(z_k). Here f(z) = z4 - 1 and f'(z) = 4z3. The method converges to one of the 4 roots depending on the starting point z_0. Choose each point in the complex plane with coordinates between -1 and 1 and determine which of the four roots it converges to, and plot the point either white, red, green, or blue accordingly. If Newton's method doesn't converge after 100 iterations, color the point black. Name your program Newton.java.

    Newton's method

  13. Gauss multiplication. Implement complex multiplication using only 3 floating point multiplications (instead of 4). You may use as many as 5 floating point additions. Answer: Gauss gave the following method to multiply (a + bi)(c + di). Set x1 = (a + b)(c + d), x2 = ac, x3 = bd. Then the product is given by x + yi where x = x2 - x3, y = x1 - x2 - x3.
  14. Rational numbers. Create a data type Rational.java and BigRational.java for positive rational numbers.
  15. Rational numbers. Modify Rational.java to provide support for negative rationals and zero.
  16. Quaternions. In 1843, Sir William Hamilton discovered an extension to complex numbers called quaternions. Quaternions extend the concept of rotation in three dimensions to four dimensions. They are used in computer graphics, control theory, signal processing, and orbital mechanics, e.g., command for spacecraft attitude control systems. (Reference: Wikipedia.) are related to Pauli spin matrices in physics. A quaternion can be represented by a 4-tuple of real numbers (a1, a2, a3, a4). The quaternion conjugate is (a1, -a2, -a3, -a4). The quaternion norm is sqrt(a12 + a22 + a32 + a42). The inverse of a quaternion is (a1/d, -a2/d, -a3/d, -a4/d) where d = a12 + a22 + a32 + a42. The sum of two quaternions (a1, a2, a3, a4) and (b1, b2, b3, b4) is (a1+b1, a2+b2, a3+b3, a4+b4), the product is (a1b1 - a2b2 - a3b3 - a4b4, a1b2 + a2b1 + a3b4 - a4b3, a1b3 - a2b4 + a3b1 + a4b2, a1b4 + a2b3 - a3b2 + a4b1), and the quotient is the product of the inverse of (a1, a2, a3, a4) and (b1, b2, b3, b4). Note that ab doesn't equal ba in general. Create a data type for quaternions. Include operations for adding, multiplying, inverting, conjugating, and taking the norm of quaternions.
  17. Equipotential surfaces. An equipotential surface is the set of all points that have the same electric potential V. Given a group of n point charges, it is useful to visualize the electric potential by plotting equipotential surfaces (aka countour plots). Program Equipotential.java draws a line every 5V by computing the potential at each gridpoint and checking whether the potential is within 1 pixel of a multiple of 5V. Since the electric field E measures how much the potential changes, E * eps is the range that the potential changes in a distance of 1 pixel.

    Electric equipotential                Electric equipotential

    It is also interesting to plot the field lines and the equipotential lines simultaneously. The field lines are always perpendicular the the equipotential lines.

  18. UN Countries. Create a data type Countryfor UN countries. Include fields for 3 digit UN Code, 3 letter ISO abbreviation, country name, and capital. Write a program Country.java that reads in a list of countries and stores them in an array of type Country. Use the method String.split to help parse the input file.
  19. Area codes. Create a data type for telephone area codes in North America. Include fields for the area code, the city, and state, and the two letter state abbreviation. Or for international phone codes. Include a field for zone, code, and country.
  20. Congressional districts. Create a data type for places, counties, and congressional districts. Include fields for place name, county name, county code, zip code, congressional district, etc. Use the data sets from the 1998 FIPS55-DC3 Index: Pennsylvania (2MB) or all 50 states plus DC and 9 outlying areas (30MB).
  21. Latitudes and longitudes. For USA latitudes and longitudes, use the TIGER database or www.bcca.org or gazetteer. For the rest of the world, use earth-info.
  22. Astronomy. Data for asteroids, meteors, and comets.
  23. Fortune 1000 companies. Create a data type the for Fortune 1000. Include fields for company name and sales revenue in millions of dollars. Data taken from April 15, 2002 issue of Fortune. Note: currently need to parse data.
  24. Elements. Create a data type Element.java for the Periodic Table of Elements. Include fields for element, atomic number, symbol, and atomic weight. (Ignore fields for boiling point, melting point, density (kg/m3), Heat vapour (kJ/mol), heat fusion (kJ/mol), thermal conductivity (W/m/K), and specific heat capacity (J/kg/K) since it's not know for all elements). Fields are separated by one or two "\t" characters. Data from here.
  25. Molecular weight. Write a program so that the user enters a molecule H2 O and the program calculates its molecular weight.
  26. Some potentially useful datafiles: aroma therapies, nutritional information, meteorological glossary, psychiatric disorders, words translated in 15 languages, dictionary of emoticons, meanings of common names, World Almanac facts about countries.

Lessons

  1. Include the method toString to get customized output when printing out an object.