Lab 5 Functions and Ancient Numerals 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 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; //find the decade decade = 1000; while(decade >= val) decade /= 10; //once we hit 0, return 0 if(!decade) return 0; //find the multiplier multiplier = val / 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> 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: indian.h indian.cpp roman.h roman.cpp hebrew.h hebrew.cpp greek.h greek.cpp menu.h menu.cpp main.cpp 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: //Purpose: //Authors: 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: Roman: Sestersii Greek: Drachma Indian: Rupee Hebrew: Shekel 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. Good luck, and enjoy!