In this lab, you will be expanding on the work in Lab 4. The self
lab is a group project which builds on the guided part of lab. The
main focus here is creating more complex applications through the
use of functions.
Introduction
========================================
Having invented a way to track sheep, Reg and Stan have become
fabulously wealthy. (Really it wasn't the sheep that did it. They
won a massive patent infringement suit against the Romans for "Roman
Numerals"). They, of course, had a problem. They had more
sestertii than they knew what to do with.
"Did you ever see so much silver?" Stan said, his eyes gaping wide
at the large budget of coins brought by the centurion.
"No." Reg replied. Reg looked very introspective, as shepherds are
want to do. "I suppose we'd better expand our fields!"
"Brilliant idea!," Stan replied. They then set about buying all of
the adjoining land to theirs. This, in turn, produced a runaway
recursive problem. "You know, Reg. If we keep buying all the land
that touches our ever expanding borders, we'll end up trying to buy
the whole continent?!" Reg replied "Oh yeah. Maybe we should start
buying some more sheep then." And that is precisely what they did.
Unfortunately, they had bought so much land, that all the sheep in
the Roman Empire would not fill their fields.
"I guess we'll have to travel long and far looking for more sheep."
Stan said one day. So the two set out into the world. They went to
India first. They discovered that the Indian sheep were tagged with
prices which were in some strange alphabet. "What is this?" Stan
said pointing at the marks "123". The Indian merchant replied
"That's One Hundred and Twenty Three Rupees." Stan quickly realized
that there was more than one way to count numbers. This first
number system they encountered was the Indian numeral system, which
we incorrectly call "Arabic Numerals" thanks to a misunderstanding
by an 11th century English cleric. The reader should already be
familiar with these numbers, as they are the number system used the
whole world over in the modern era.
"Well, the Indian number system is very nice! I especially liked
the 0." Reg said as they were leaving. "Eh, it will never catch on"
replied Stan.
After buying all the sheep in India, and making broad swaths through
Arabia, Reg and Stan encounter yet another way of printing prices.
They found a Jewish Shepard named Jethro (yes, that is a real Hebrew
name!). Jethro had a very nice ram which was labeled with
(transliterated) "DTs". "Stan, what do you suppose that strange
mark is?" Jethro explained, "Those are Hebrew letters, but here
they are showing a number. This ram is worth 94 Shekels." "94
Shekels, that's quite a deal!", exclaimed Stan. They handed over the
appropriate amount of silver, and the ram was theirs. Not missing
an opportunity to learn something new, Reg asked Jethro about the
Hebrew number system. Jethro explained the Hebrew alphabet, and how
they had a system where each letter represented a number. He went
on to show them how Hebrew is read from right to left. Stan took
notes, however, given that Stan was not adept at forming the Hebrew
letters, he wrote down their names, inventing a Romanized
transliteration for each, and also wrote down their numeric values.
Stan's notes are as follows:
Name Sound Value
---- --------- -----
Aleph * (none) 1
Bet B 2
Gimel G 3
Dalet D 4
Hei H 5
Vav V 6
Zayin Z 7
Het Ch 8
Tet T 9
Yud Y 10
Kaf K 20
Lamed L 30
Mem M 40
Nun N 50
Samech S 60
Ayin ^ (none) 70
Pei P 80
Tsadi Ts 90
Kuf Q 100
Resh R 200
Shin Sh 300
Tav Ta 400
NOTE: If you are interested in the shape of these letters, just
google "Hebrew Alphabet" and you'll find it. There are
some wonderful coincidences in the Hebrew number system.
For instance, the word for father is "Ab", the word for
mother is "Haim" and the word for child is "Yaled". If we
use our transliterated Hebrew numbers, we have B*=3, M*=41,
DLY = 44. Thus "Mother + Father = Child".
They thanked Jethro, and they departed from the land of Judea and
made their way back to Latinum. They were a bit puzzled by the
silent letters, but they decided they could distinguish between them
in Roman characters by using * for aleph and ^ for ayin.
Along the way back to their peninsula, they passed through
Greece. While in Greece they encounter a beautiful ewe. The ram
they bought in Judea agreed that the ewe was beautiful, and before
they could stop him, the ram expressed his admiration for the ewe in
the way which sheep generally do! "You have soiled my pure bred
sheep!" Screamed Aristophanes the Shepherd. "I am terribly sorry,
but he got out of our hands." Reg said, in his most placating tone.
"Since she is ruined for pure breeding, I think it only fair that we
buy her from you.", said Stan. Aristophanes ignored Reg, but Stan's
offer made sense.
"How much?" asked Reg. Like all sheep, this Ewe had a price tag.
The price tag read "TA". "How much is that?" Stan asked. "301
Drachmas" replied Aristophanes. "301 Drachmas! That's almost 5
times what we paid for the ram." shouted Reg, kicking the beast.
"She is of a very rare breed, a fine line of sheep." Replied
Aristophanes. They both sighed and paid for the sheep. In
exchange, Aristophanes showed them the Greek Number system. Once
again, being not at all used to printing out the strange characters
of Greece, Stan wrote out their names, sound, and value.
Name Sound Value
---- ----- -----
Alpha A 1
Beta B 2
Gamma G 3
Delta D 4
Epsilon Eh 5
Vau Va 6
Zeta Zd 7
Eta Ee 8
Theta Th 9
Iota Ey 10
Kappa K 20
Lambda L 30
Mu M 40
Nu N 50
Ksi X 60
Omicron O 70
Pi P 80
Koppa Ku 90
Rho R 100
Sigma S 200
Tau T 300
Upsilon Iy 400
Phi F 500
Chi Ch 600
Psi Ps 700
Omega Aw 800
Sampi Sa 900
Note: The astute reader will note the presence of a few extra
letters. These letters are Vau, Koppa, and Sampi. These letters
are alternate forms of Greek letters, basically indicating a
different kind of stop for the consonants they represent. These
letters were considered obsolete by about 403BC when Athens
adopted the Ionian local variant of Greek spelling. They were
still used for numbering though, otherwise the decades wouldn't
work out!
Also, I have taken a few liberties. Originally, Greek was written
right to left, as was Phoenician (from which it descends.) I have
opted to use left to right, however, so that only the Hebrew
section will be truly difficult. However, given the apparent time
frame of our story, Greece would still have been writing from
right to left. Sorry for the anachronism!
Now armed with a Judean ram, a Greecean ewe, and several soon to be
Greco-Jewish lambs, Reg and Stan returned to the land of Tuscani
where they put their new herds to pasture and passed on knowledge of
the foreign number systems to their countrymen.
The task that is now before us is to help Reg and Stan carry out
international commerce in the ancient world. We will suppose that
they have a computer, one which can print only Latin characters, and
they wish to trade with their neighboring countries. We want to be
able to readily convert from any number system to any other number
system. For Hebrew and Greek, we will use Stan's phonetic
representations for our characters. That is, anytime you want an
"Aleph" your program is going to print "*" and anytime you want a
"Beta" your program will print "B". For the Greek letters this will
almost work correctly anyway. The Romans, being ever jealous of the
Greeks, stole a significant portion of the Latin alphabet from the
Greek alphabet. (Even the name "alphabet" derives from the first
two letters in Greek.)
Lab 5.1 - Guided Refactoring
============================
In order to accomplish this large task, we are first going to
refactor the roman numeral program into a program which uses
functions. Refactoring is the process of reorganizing code without
changing its function. We should get away with rewriting very
little of the program. This will provide us with functions that we can
use in the self part of the lab, which you will be doing in groups.
The first thing we want to do is to set up the prototypes of our
functions. I would recommend doing this in a copy of roman.cpp,
that way if you mess up too much, you can always revert back to your
working program. Some of this will be simple reorganization.
We are going to create three functions:
int nextRomanVal(int val);
void printRomanDigit(int val);
void indianToRoman(int num);
The basic idea is that "nextRomanVal" will give us our next
divisor, "printRomanDigit" will print out the digit for the given
value, and "indianToRoman" will take in an integer, and print it in
Roman numerals. Once you add these prototypes, the top of your new
roman.cpp file should read as follows:
#include <iostream>
using namespace std;
int nextRomanVal(int val);
void printRomanDigit(int val);
void indianToRoman(int num);
Now, we want to skip past the main function, and write the
nextRomanVal function. This function is going to work just a little
bit differently than the counter system we used in the main
function. Basically, "val" contains all the information we need. We
just need to break it apart into its components of multiplier and
decade. In short, we are going to factor "val". Normally factoring
can be a long process (such is the basis of encryption), but here
it's easy. We know one of the factors will be either 1000, 100, 10,
or 1. After we have the decade, finding the multiplier is a piece
of cake! Add this function below your main function. Take a moment
and think through how this works so the logic will make sense to
you:
// Returns the next value for consideration in Roman Numeral
// Computation
int
nextRomanVal(int val) {
int multiplier;
int decade;
//update the value
switch(multiplier) {
case 9:
val = 5 * decade;
break;
case 5:
val = 4 * decade;
break;
case 4:
val = 1 * decade;
break;
case 10:
val = decade * 9;
break;
}
return val;
}
Now we are going to turn our attention to the "printRomanDigit"
function. This is really just a cut and paste job from your main
function. I'll state it here in its entirety and leave the cut and
pasting up to you. Place this function below the "nextRomanVal" function:
// Prints out the correct roman string for a given value.
void
printRomanDigit(int val) {
//output the correct symbol
switch(val) {
case 1000:
cout << "M";
break;
case 900:
cout << "CM";
break;
case 500:
cout << "D";
break;
case 400:
cout << "CD";
break;
case 100:
cout << "C";
break;
case 90:
cout << "XC";
break;
case 50:
cout << "L";
break;
case 40:
cout << "XL";
break;
case 10:
cout << "X";
break;
case 9:
cout << "IX";
break;
case 5:
cout << "V";
break;
case 4:
cout << "IV";
break;
case 1:
cout << "I";
break;
}
}
Now, in our penultimate step, we are going to write
"indianToRoman". This function does pretty much what your old main
function did. Notice now, however, that the function is shorter
than your old main was because it now uses the two function we have
just now defined. Enter this function below "printRomanNum":
// Receives an Indian number (an int) and prints it as a Roman Numeral
void
indianToRoman(int num) {
int val=9000;
int i,n;
// run through all decades
while(val) {
n = num / val;
for(i=0; i<n; i++) {
printRomanDigit(val);
}
// update num and val
num = num % val;
val = nextRomanVal(val);
}
cout << endl;
}
Our final step is to rework the main function. Now that we have the
three functions which are listed above, the main becomes laughably
simple. Here is our main function, alter yours to match it:
int
main(void)
{
int num;
//get the number
cout << "Number: ";
cin >> num;
//convert to roman
indianToRoman(num);
return 0;
}
Now, compile the code and make sure it works. Take a moment to read
through it all a few times so that the logic of this operation
become clear. Also, notice the subtle changes to the program which
make it more modular. We have taken a huge unreadable block of
code, and turned it into something nice by splitting it apart into
functions.
Lab 5.2 (Self, Group) Building a Large Program
===============================================
In this part of the lab, you are going to build a program which can
convert between the three number systems. An example run of this
system can be found below:
--Begin Sample Run--
Welcome to Reg and Stan's Number Writer 500(BC)
What number system would you like to start with?
1.) Roman/Etruscan
2.) Indian
3.) Hebrew
4.) Greek
Choice? 1
Roman Number: CCXII
What number system would you like to convert to?
1.) Roman/Etruscan
2.) Indian
3.) Hebrew
4.) Greek
Choice? 4
Greek Number: SEyAA
-- End Sample Run --
Additionally, your program should provide error checking for the
menus. Extra credit will be awarded for programs which perform
error checking on the number entry screens.
Group & Decomposition Details
-----------------------------
You will be working in groups of 4. If you can't find a group to
join, let me know and I will assign you to one. You will need to
create a set of files to work together. Each group member will be
responsible for some set of functions. The breakdown of files in my
sample version of the program are as follows:
Additionally, I wrote unit test files for each of the sub systems,
so I had "indianTest.cpp", "romanTest.cpp", hebrewTest.cpp",
"greekTest.cpp", "menuTest.cpp". I would recommend that each person
in the group be assigned one of the subsystems and that they develop
their files and their test files.
Because compilation will be a pain, given the large number of files,
you will want to create a makefile for this project. Instructions
for writing make files will be provided in class.
Turnin
------
At the top of each file I want to see the following comment block:
//File: <filename>
//Purpose: <purpose>
//Authors: <list of authors who worked on this file>
This way I will know who did what. If someone didn't pull their
weight, they get penalized in the grading. Each group will submit
just one program, however.
Pick someone to be your group's leader. They will be responsible
for putting together the final program, and turning it in using the
turnin script.
Hints
-----
- The Indian numeral system is the easiest as it uses standard
integers. Indian numerals are, in fact, your internal storage
mechanism. So the steps for any conversion are "convert to Indian,
then to the other system."
- The Roman numerals are the hardest to convert to indian. The
other systems have no special rules. They are completely
additive. (They are almost base 10!)
- I followed a general pattern for all of my conversions. For
instance, for roman.h and roman.cpp I defined the following functions:
int nextRomanVal(int val);
void printRomanDigit(int val);
void indianToRoman(int num);
int romanToIndian();
- When converting from the letter based systems, you'll have to read
in single characters of input and respond accordingly.
Alternatively, and for extra credit, you could research strings
and store the phonetic numbers.
- Note that the hebrew letters are printed right to left. This
means you'll have to extract them backwards. This isn't too bad
though, given the simplicity of the system. Try doing a few
manual calculations starting at the bottom part first.
- For Hebrew, Roman, and the Greek set, you won't be able to go
above different boundaries. The highest number for each system is
therefore:
Roman: 3999
Hebrew: 499
Greek: 999
In all these systems, there are ways to write larger numbers, but
the rules become complex, and difficult to render in ASCII. If
you find a way to render them in ascii, I will be generous with
extra credit.
- The menu pattern example we did in class is really really really
similar to what you need to do here. I would just copy the code
from D2L and use that with some tweaks for my menu system.
Big-time Extra Credit (20 points on Midterm Exam)
------------------------------------------------
Reg and Stan are merchants, really. They would be very interested
in being able to convert currency as well as numbers. The currency
in the ancient world was based on weights of precious metals. The
currencies mentioned in the story are:
Note that some of these coins exist now, but they are no longer made
of silver or gold. Instead, they are now "fiat money". If you do a
little bit of research, you can establish a base price in ounces of
silver for all of the ancient values. Then you can convert money
from one denomination to another. If you alter your program so it
also shows the money conversion, I will reward you richly. Not with
silver or gold, but something far rarer and more sought after.
Points on your exam!
Example:
Suppose I choose greek in the first menu. The number I enter will
be assumed to be in Drachmas. Then suppose I choose roman in the
second menu. This will still change the number, but it will also
show me the value in Sestersii, but the value will be printed in
Roman numerals.