The Tiny RPN Calculator: Version 1.01 Overview

Extending the Calculator

It's important to realize, first, that our goals for this draft are—and should be—quite modest. This draft implements only one programmable sequence of commands. Additionally, storage of this sequence remains volatile for the time being, inasmuch as the calculator will retain the program only until it is overwritten by another program, or until the user exits the calculator on the command line. These decisions are deliberate. For the moment our goal is simply to see whether we can get some sort of programming function to work in this calculator. Naturally, we would like to invest the calculator with abilities to create numerous programs, and store them in a less volatile medium such as files. But as you'll discover in time, it will take four full drafts of the program—Versions 1.01 through 1.04—before all of these features are put into place. These decisions are also deliberate, especially the decision to defer more permanent storage of programs until Version 1.04.

Therefore, Version 1.01 extends the capabilities of v1.00 only insofar as it allows the user to create and invoke exactly one programmable sequence of commands. To this end the class Program is introduced, and an instance of Program, called program, is made a member of the Calculator class. Since there is only one program available, this program is put in charge of its own functioning, chiefly through the public method Program::CheckOperation(), which takes the address of the string entry as its parameter. If the entry reads "pgm", the calculator is instructed to get program instructions from the user via the Set() method. If the entry reads "run" instead, then the Boolean variable isRunning is set to true and the instruction count to zero. If the calculator is currently running a program, it retrieves the next instruction and assigns it to the string entry. (This is why the CheckOperation() method needs to take the address of entry rather than make a local copy.)

Note that in the Program class, each set of instructions is stored as a series of strings inside a container of type vector. Like the other container classes, vectors comprise an important part of the C++ standard library. C++ programmers know that vectors are extremely useful and easy to implement inasmuch as they behave like "smart arrays." They keep track of the number of elements they contain, and they automatically adjust their capacity as more and more elements are added. Note as well that in the Calculator::Run() method, the loop has been altered to account for two scenarios: one in which instructions are input manually, and one in which instructions are being read one-by-one from the vector<string> variable instructions of the object program. Finally, observe that when the user has typed the instruction pgm, the Run() method now intercepts it by means of a conditional statement with an empty consequent condition. If this statement were not there, the entry would simply fall to the bottom of the if-then-else block, and the calculator would report the string "pgm" as being a nonexistent math function—an action that of course we'd like to avoid.

Using the Programmability Feature

Now it's time to exploit the calculator's programmability, and determine what we get from an empirical exploration. We start with a simple program that verifies the following identity: (5½ + 1) / 2 = 1 / ((5½ - 1) / 2) . To create the program, we take the following steps: (1) Enter the command pgm; (2) When prompted by the calculator, enter our string of instructions; (3) Terminate the string of instructions with the command end, then press <Enter>:

A Tiny RPN Calculator (;-}=   v1.01

pgm
Enter a sequence of program instructions; terminate by entering "end": 5 sqrt 1 + 2 / ? 5 sqrt 1 - 2 / r ? end
   Program created.

To run the program, we simply enter the command run, as shown below:

pgm
Enter a sequence of program instructions; terminate by entering "end": 5 sqrt 1 + 2 / ? 5 sqrt 1 - 2 / r ? end
   Program created.
run
   1.61803398875
   1.61803398875

The programmability feature appears to work as promised. However, our choice of a first example is about as exciting and useful as the ubiquitous "Hello, world!" program, because in either case the program does not accept inputs, and always outputs the same result time and again. Let's do something more constructive: we will program one of the trigonometric identities from Exercise 7 of the Version 1.00 Overview, and test this identity with a variety of inputs:

pgm
Enter a sequence of program instructions; terminate by entering "end":
A = A 2 * tan ? 2 A tan dp sq 1 sw - / * ? end
   Program created.
2 run
   1.15782128235
   1.15782128235
e run
   -1.13060637695
   -1.13060637695
3 run
   -0.291006191385
   -0.291006191385
pi run
   -2.44921270764e-16
   -2.44921270764e-16
4 run
   -6.79971145522
   -6.79971145522

Now this is looking more like fun! Note that our program begins by assigning the input to the variable A before it processes this input. Note also that when we attempt to input the number pi, we expect an output of zero on both sides of the equation; yet the program outputs not zero, but a very small number that approximates to zero. This phenomenon occurs for at least two reasons. One is that since pi is not only irrational but also a transcendental number, we have no choice but to input a number that approximates to pi. Two, the precision of floating-point arithmetic in computers is dogged by the phenomenon of representation error, which stems from the fact that most decimal numbers cannot be represented accurately as binary fractions, or sums thereof.

Looking Ahead

We took a giant step forward in making the Tiny Calculator programmable. Wouldn't it be nice, though, if we could extend the calculator so that it can store and run a variety of different programs, instead of just one? Moreover, there may be occasions in which we'd like to concatenate, or chain together, two or more programs to solve a single problem. We will address these issues as we extend the calculator in Version 1.02. As we do so, some major changes to the Program class will be inevitable. For one thing, the run command will no longer suffice; if we are to have more than one program available to us, it's obvious that these programs will have to be created and invoked by name. Second, it would seem that the Program class will have to surrender control of its own functioning to some other entity—perhaps an entity responsible for creating, naming, storing, retrieving, and otherwise managing each program in a collection of programs. You can anticipate, therefore, that Version 1.02 will implement a ProgramManager class to perform these essential tasks.

Exercises

1) Write a program that verifies the trigonometric identity of the example above, but instead of assigning input to a variable, use stack functions. Test your program by inputting a variety of angular values—including, presumably, some values you've already seen.

2) Write a program that computes the raw displacement of an engine measured in metric units. The user will enter bore, stroke, and number of cylinders in that order, then type run. Use stack functions to perform the computation, then store the raw displacement, expressed in cubic millimeters, in the variable D. In your program, use this variable to produce three formatted outputs: (a) displacement in cubic centimeters, rounded to the nearest cubic millimeter; (b) displacement in cubic centimeters, rounded to the nearest cubic centimeter; (c) displacement in liters, rounded to the nearest tenth of a liter. Use as your examples the Vincent Black Shadow motorcycle (bore: 84 mm.; stroke: 90 mm.; 2 cylinders); the Laverda V6 motorcycle (bore: 65 mm.; stroke: 50 mm.; 6 cylinders); and the Porsche Carrera GT Tech (bore: 98 mm.; stroke: 76 mm.; 10 cylinders).

3) The formula for calculating compound interest may be expressed as  A = P(1 + r / 100 / n)yn , where A is the amount recouped on the investment, P is the principal invested, r is the annual rate expressed as a percentage, n is the number of times per year that interest is compounded, and y is the length of the investment term in years. Using this formula, write a program to calculate the amount recouped on an investment. Your inputs should be principal, rate, investment term, and number of times compounded per year, in that order. Your output should be formatted in a way that makes sense (or "cents," as the case may be!). Test your program on the following investments: (a) $500 at 4.5 percent compounded annually for two years; (b) $7,500 at 2.8 percent compounded quarterly for 5½ years; (c) $3,000 at 6 percent compounded bimonthly for 10 months; (d) $420 at 3.5 percent compounded monthly for 29 months; (e) $1,200 at 1.9 percent compounded weekly for 1¾ years; (f) $90,000 at 0.9 percent compounded daily for one month; (g) $90,000 at 0.9 percent compounded daily for 17 months; (h) $21,000 at 2.375 percent compounded daily for 657 days. (Hint: Your program should store the number of times compounded per year in the variable N before it does anything else.)

4) Think of your own applications in which the Tiny Calculator's programmability might prove useful, and implement them.

Solutions to Exercises

1) Here is one possible solution. Note that we've inserted a newline character (with a press of the <Enter> key) prior to typing the sequence of instructions. This is perfectly acceptable, because the calculator ignores all whitespace characters, including newlines, as it loads the instructions into the program. We will use the newline character from time to time in order to keep the instructions confined within the gray container for them:

pgm
Enter a sequence of program instructions; terminate by entering "end":
dp 2 * tan ? sw tan dp 2 * sw sq 1 sw - / ? end
   Program created.
2 run
   1.15782128235
   1.15782128235
e run
   -1.13060637695
   -1.13060637695
5.55 run
   -9.54135166228
   -9.54135166228
70 9 / run
   -0.153598828311
   -0.153598828311
-244 7 / run
   -0.683032432546
   -0.683032432546
22.5 rad run
   1
   1
44.99 rad run
   2864.7888593
   2864.7888593

2) The solution is as follows:

pgm
Enter a sequence of program instructions; terminate by entering "end":
* sw 2 / sq pi * * D = D round 1000 / ? D 1000 / round ? D 100000 / round 10 / ? end
   Program created.
84 90 2 run
   997.518
   998
   1
65 50 6 run
   995.492
   995
   1
98 76 10 run
   5732.653
   5733
   5.7

3) Here is one possible solution:

pgm
Enter a sequence of program instructions; terminate by entering "end": 
N = N * sw 100 / N / 1 + sw yx * 100 * round 100 / ? end
   Program created.
500 4.5 2 1 run
   546.01
7500 2.8 5.5 4 run
   8743.99
3000 6 10 12 / 6 run
   3153.03
420 3.5 29 12 / 12 run
   457.01
1200 1.9 7 4 / 52 run
   1240.56
90000 0.9 1 12 / 365 run
   90067.52
90000 0.9 17 12 / 365 run
   91154.83
21000 2.375 657 365 / 365 run
   21917.19