15110 Spring 2012 [Touretzky/Kaynar]

Programming Assignment 2 - due Tuesday, September 11

Note: You are responsible for protecting your solutions to these problems from being seen by other students both physically (e.g., by looking over your shoulder) and electronically. In particular, since the lab machines use the Andrew File System to share files worldwide, you need to be careful that you do not put files in a place that is publicly accessible.

If you are doing the assignment on the Gates-Hillman Cluster machines we use in lab or on unix.andrew.cmu.edu, our recommendation is that you create a pa2 directory under ~/private/15110 for this assignment. That is, the new directory pa2 is inside a directory called 15110, which is inside the directory called private, which is inside your home directory. (Every new andrew account is set up with a private subdirectory within the account's home directory that only that account can access.) Please refer to Setting up Directories for information about managing your directories.


For this assignment, you will create a Ruby source file (that is, a text file containing Ruby code) for each of the problems below. You should store all of these files in a folder named pa2, which you will zip up and submit.

As you will discover this semester, computer programs are rarely correct when they are first written. They often have bugs. In addition to writing the code, you should test your code on multiple inputs, for which you independently know the correct output (e.g., by plugging the inputs into a calculator).

The Formulas

Write Ruby functions to calculate each formula as indicated below. The calculations should be performed with the full precision shown in the examples.

  1. Einstein's theory of special relativity says that the faster a spaceship travels, the more slowly its clock runs relative to a stationary observer. The formula for this time dilation, called the Lorentz transformation, is: \[d = \sqrt{1-v^2/c^2} \] where \(v \) is the spaceship's velocity and \(c\) is the speed of light. A time dilation value of 0.9 would mean that the clock on the moving space ship would be running at 90% of the rate of a clock on the ground, so people on the ship will think they've been flying for less time than people on the ground who are observing them.

    Note: In the above equation, choice of units for speed does not matter as long as \(v\) and \(c\) are expressed in the same units, be it miles per hour or meters per second. We can simplify the problem by using ``the speed of light'' as our units, which means \(c\) is 1 and \(v \) is velocity expressed as a fraction of \(c\).

    1. [1 point] Use a calculator to calculate the time dilation for the case where \( v \)= 0.5 \(c\) and the time dilation for the case where \(v\) = 0.707 \(c\). Then create a text file dilation.rb that includes the definition of a Ruby function dilation(vc_ratio). This function should calculate and return the time dilation for the velocity (expressed as a fraction of \(c\)) given as a parameter.

      You should be able to use the dilation(vc_ratio) function in irb as follows:

      >> load "dilation.rb"
      => true
      >> dilation(0.5)
      => 0.866025403784439
      >> dilation(0.707)
      => 0.707213546250353
    2. [1 point] George jumps in his spaceship and flies at 0.5 c (half the speed of light) for 3 hours (by his watch). At the same time, Jane jumps in her spaceship and flies at 0.707 c for 2.5 hours (by her watch). If they took off at noon, what time was it when each one returned? Answer this question by creating a text file return_time.rb that includes a Ruby function return_time(start,vc_ratio,duration). You should be able to use the function return_time(start,vc_ratio,duration) in irb such that return_time(12,0.5,3) evaluates to (returns) George's return time and return_time(12,0.707,2.5) evaluates to (returns) Jane's return time. You are not required but permitted to use the function you wrote in part a.

      Hint: Jane flies for less time (by her watch), but George beats her home.
  2. [1 point] For a mortgage with a principal amount of \(P\) dollars, an interest rate of \(i\) per year (expressed as a decimal fraction such as 0.04 for 4%) for \(n\) years, the final debt amount \(M\) including the principal can be calculated by the formula

    \[M = P(1 + i)^n.\]

    Define a Ruby function called final_amount(principal_amount, interest_rate, num_years) in final_amount.rb that returns the final amount M of debt calculated from the principal amount, interest rate and the number of years for the mortgage. Test your function.

  3. [1 point] Consider Newton's second law, which can be expressed by the formula, \[F = ma.\] Create a text file force.rb and define in that file a Ruby function force(m,a) that prints (in the format shown below) the amount of force needed to cause an acceleration equal to a on an object that has a mass of m, placing the function in force.rb. What force in Newtons (1 N = 1 kg m/s2) is needed to accelerate a 2.5kg object at 3m/s2? Do the calculation by hand and using your Ruby function and verify that your Ruby function produces the correct result.

    Example usage:

    >> load "force.rb"
    => true
    >> force(2.5,3.0)
    The force is 7.5 Newtons.
    => nil
  4. The volume of a cylinder (in cubic meters) can be calculated from the radius \(r\) (in meters) of its base and its height \(h\) (in meters) using the formula:

    \[V = \pi r^2 h.\]
    1. [1 point] Define a Ruby function in cylinder.rb called cylinder_volume(r,h) that calculates and returns the volume of a cylinder. Use Math::PI for \(\pi\).

    2. [1 point] In cylinder.rb, define a Ruby function print_half_volume() that calculates half of the volume occupied by a cylinder with radius 10m and height 15m. It should return nil after printing the following line of text:

      The cylinder can be cut into two pieces each of which has volume XXXX.XXXXXXXXXXX.

      (Replacing XXXX.XXXXXXXXXXX with the calculated volume.)

      Your print_half_volume() function should be defined without calculating the volume of the cylinder itself; it should call the cylinder_volume function you wrote for part a.

  5. [2 points] Consider a cubic polynomial function of the form:

    \[f(x) = ax^3 + bx^2 + cx + d.\]

    In list_cubic1.rb, define a Ruby function called list_cubic1(a, b, c, d) that prints a list of the values of f(x) for x = 0 to x = 20 (inclusive), given the coefficients of the polynomial in the order shown. Your function should use a loop rather than repeating the code for the calculation 21 times. Use the formula directly to compute these values. The function should always return nil.

    For example, if your polynomial is \(f(x) = 3x^3 + 4x^2 - 3x + 2,\) then the output would look like:

    >> load "list_cubic1.rb"
    => true
    >> list_cubic1(3,4,-3,2) 
    => nil

    Be sure to test your function using a few more polynomials besides this one to be more confident that your function is correct.

  6. [2 points] An alternate way to compute the values of a polynomial function is to use the method of finite differences that was used in Babbage's Difference Engine.

    In list_cubic2.rb, define a Ruby function called list_cubic2(d3f0, d2f0, df0, f0) that prints a list of the values of f(x) for x = 0 to x = 20 (inclusive), given the values of \(\Delta^3{}f(0)\), \(\Delta^2{}f(0)\), \(\Delta{}f(0)\), and \(f(0)\), respectively. Your function should use the method of finite differences to compute the function values. The function should always return nil.

    For example, consider the calculation of the values for the polynomial, \(f(x) = 3x^3 + 4x^2 -3x + 2.\) Using the method in described in the lecture, we can compute the \(\Delta\) functions by hand to be:

    \(\Delta^3f(0)= 18\)
    \(\Delta^2f(0) = 26\)
    \(\Delta f(0) = 4\)
    \(f(0) = 2\)

    Thus, list_cubic2(18, 26, 4, 2) can be used to list the values for this polynomial:

    >> list_cubic2(18, 26, 4, 2)
    => nil

    Be sure to test your function using a few more polynomials besides this one to be more confident that your function is correct.


You should now have a pa2 directory that contains the files dilation.rb, return_time.rb, final_amount.rb, force.rb, cylinder.rb, list_cubic1.rb, list_cubic2.rb each containing the corresponding function (corrected). Zip up your directory and hand it in.