370 likes | 550 Views
CS 144 Advanced C++ Programming March 5 Class Meeting. Department of Computer Engineering San Jose State University Spring 2019 Instructor: Ron Mak www.cs.sjsu.edu/~mak. Assignment #5 Sample Solution. #include <string> using namespace std ; class RomanNumeral { public: /**
E N D
CS 144Advanced C++ ProgrammingMarch 5 Class Meeting Department of Computer EngineeringSan Jose State UniversitySpring 2019Instructor: Ron Mak www.cs.sjsu.edu/~mak
Assignment #5 Sample Solution #include <string> using namespace std; class RomanNumeral { public: /** * Default constructor. */ RomanNumeral(); /** * Constructor. * @paramstr the Roman numeral string. */ RomanNumeral(string str); /** * Constructor. * @param value the decimal value of the Roman numeral. */ RomanNumeral(int value); RomanNumeral.h
Assignment #5 Sample Solution, cont’d RomanNumeral.h /** * Getter. * @return the Roman numeral string. */ string get_roman() const; /** * Getter. * @return the decimal value. */ intget_decimal() const; /** * Overloaded operator to add two Roman numerals. * @param other the other numeral to add to this one. * @return the sum Roman numeral. */ RomanNumeral operator +(constRomanNumeral& other) const;
Assignment #5 Sample Solution, cont’d RomanNumeral.h /** * Overloaded operator to subtract two Roman numerals. * @param other the other numeral to subtract from this one. * @return the difference Roman numeral. */ RomanNumeral operator -(constRomanNumeral& other) const; /** * Overloaded operator to multiply two Roman numerals. * @param other the other numeral to multiply this one. * @return the product Roman numeral. */ RomanNumeral operator *(constRomanNumeral& other) const; /** * Overloaded operator to divide two Roman numerals * (integer division). * @param other the other numeral to divide this one. * @return the quotient Roman numeral. */ RomanNumeral operator /(constRomanNumeral& other) const;
Assignment #5 Sample Solution, cont’d RomanNumeral.h /** * Overloaded operator for equality. * @param other the other Roman numeral to compare to. * @return true if they're equal, otherwise true. */ bool operator ==(constRomanNumeral& other) const; /** * Overloaded operator for inequality. * @param other the other Roman numeral to compare to. * @return true if they're unequal, otherwise true. */ bool operator !=(constRomanNumeral& other) const;
Assignment #5 Sample Solution, cont’d RomanNumeral.h /** * Overloaded operator to construct a Roman numeral by * reading its string from an input stream; e.g., MMXVI. * @param in the input stream. * @param numeral the constructed Roman numeral. * @return the input stream. */ friendistream& operator >>(istream& in, RomanNumeral& numeral); /** * Overloaded operator to write a Roman numeral int the form * [decimal:string] to an output stream; e.g., [2016:MMXVI] * @param out the output stream. * @param numeral the Roman numeral. * @return the output stream. */ friendostream& operator <<(ostream& out, constRomanNumeral& numeral); Why are they friends and not member functions?
Assignment #5 Sample Solution, cont’d RomanNumeral.h private: string roman; // Roman numeral as a string int decimal; // decimal value of the Roman numeral /** * Compute the Roman numeral string from the decimal value. */ void to_roman(); /** * Compute the decimal value from the Roman numeral string. */ void to_decimal(); };
Assignment #5 Sample Solution, cont’d #include <iostream> #include <fstream> #include <string> #include "RomanNumeral.h" using namespace std; RomanNumeral::RomanNumeral() : roman(""), decimal(0) {} RomanNumeral::RomanNumeral(string str) : roman(str) { // Compute the decimal value. to_decimal(); } RomanNumeral::RomanNumeral(int value) : decimal(value) { // Compute the Roman numeral string. to_roman(); } string RomanNumeral::get_roman() const { return roman; } intRomanNumeral::get_decimal() const { return decimal; } RomanNumeral.cpp
Assignment #5 Sample Solution, cont’d RomanNumeralRomanNumeral::operator +(constRomanNumeral& other) const { RomanNumeral sum(decimal + other.decimal); return sum; } RomanNumeralRomanNumeral::operator -(constRomanNumeral& other) const { RomanNumeral diff(decimal - other.decimal); return diff; } RomanNumeralRomanNumeral::operator *(constRomanNumeral& other) const { RomanNumeral prod(decimal*other.decimal); return prod; } RomanNumeralRomanNumeral::operator /(constRomanNumeral& other) const { RomanNumeralquot(decimal/other.decimal); return quot; } RomanNumeral.cpp
Assignment #5 Sample Solution, cont’d bool RomanNumeral::operator ==(constRomanNumeral& other) const { return decimal == other.decimal; } bool RomanNumeral::operator !=(constRomanNumeral& other) const { return decimal != other.decimal; } RomanNumeral.cpp
Assignment #5 Sample Solution, cont’d istream& operator >>(istream& in, RomanNumeral& numeral) { string str; in >> str; numeral.roman = str; numeral.to_decimal(); return in; } ostream& operator <<(ostream& out, constRomanNumeral& numeral) { out << "[" << numeral.decimal<< ":" << numeral.roman<< "]"; return out; } Why not numeral->roman and numeral->to_decimal()? RomanNumeral.cpp
Assignment #5 Sample Solution, cont’d RomanNumeral.cpp void RomanNumeral::to_roman() { int temp = decimal; roman = ""; while (temp >= 1000) { roman += "M"; temp -= 1000; } if (temp >= 900) { roman += "CM"; temp -= 900; } else if (temp >= 500) { roman += "D"; temp -= 500; } else if (temp >= 400) { roman += "CD"; temp -= 400; } while (temp >= 100) { roman += "C"; temp -= 100; }
Assignment #5 Sample Solution, cont’d if (temp >= 90) { roman += "XC"; temp -= 90; } else if (temp >= 50) { roman += "L"; temp -= 50; } else if (temp >= 40) { roman += "XL"; temp -= 40; } while (temp >= 10) { roman += "X"; temp -= 10; } if (temp >= 9) { roman += "IX"; temp -= 9; } else if (temp >= 5) { roman += "V"; temp -= 5; } else if (temp >= 4) { roman += "IV"; temp -= 4; } while (temp >= 1) { roman += "I"; temp--; } } RomanNumeral.cpp
Assignment #5 Sample Solution, cont’d RomanNumeral.cpp void RomanNumeral::to_decimal() { int length = roman.length(); decimal = 0; // Scan the Roman numeral string from left to right // and add the corresponding character values. for (int i = 0; i < length; i++) { switch (roman[i]) { case 'M': decimal += 1000; break; case 'D': decimal += 500; break;
Assignment #5 Sample Solution, cont’d case 'C': if (i+1 < length) { switch (roman[i+1]) { case 'D': // CD decimal += 400; i++; break; case 'M': // CM decimal += 900; i++; break; default: decimal += 100; break; } } else decimal += 100; break; RomanNumeral.cpp
Assignment #5 Sample Solution, cont’d RomanNumeral.cpp case 'L': decimal += 50; break; case 'X': if (i+1 < length) { switch (roman[i+1]) { case 'L': // XL decimal += 40; i++; break; case 'C': // XC decimal += 90; i++; break; default: decimal += 10; break; } } else decimal += 10; break;
Assignment #5 Sample Solution, cont’d case 'V': decimal += 5; break; case 'I': if (i+1 < length) { switch (roman[i+1]) { case 'V': // IV decimal += 4; i++; break; case 'X': // IX decimal += 9; i++; break; default: decimal++; break; } } else decimal++; break; } } } RomanNumeral.cpp
chrono #include <iostream> #include <iomanip> #include <vector> #include <chrono> using namespace std; using namespace std::chrono; long time_vector_initialization(vector<int> v, int n); int main() { vector<int> v; for (long n = 10000; n <= 100000000; n *= 10) { long elapsed_time = time_vector_initialization(v, n); cout << "Elapsed_time for " << setw(9) << n << " : " << setw(4) << elapsed_time << " ms" << endl; } } TimeVector.cpp
chrono, cont’d long time_vector_initialization(vector<int> v, int n) { steady_clock::time_pointstart_time = steady_clock::now(); v.clear(); for (inti = 0; i < n; i++) v.push_back(i); steady_clock::time_pointend_time = steady_clock::now(); // Other options include: nanoseconds, microseconds long elapsed_time = duration_cast<milliseconds>(end_time - start_time).count(); return elapsed_time; } See http://en.cppreference.com/w/cpp/chrono
Assignment #6. Big Pi • You will compute and print the first 1,000 decimal digits of π. • Borwein quartic convergence algorithm • You will use the Multiple-Precision Integers and Rationals (MPIR) library. • http://mpir.org/ • The library is distributed as source files. • Enables computation using numbers with arbitrarily long precision.
Assignment #6, cont’d • Therefore, you will learn how to download the source files, and configure, build, and install the library. • Useful skills to have, because you will most likely need to use other libraries in the future. • graphics and GUI libraries • circuit simulation libraries • numerical computing libraries • data analytics libraries • etc.
Assignment #6, cont’d • Building and installing the MPIR library is straightforward on Linux and Mac OS. • Unfortunately, more complicated for Windows. • You must use Cygwin. • Recommendation: Use Ubuntu as a virtual machine instead. • Please work together to help each other build and install MPIR. • Programs must be individual work, as usual.
Assignment #6, cont’d • Submit two solutions: • Use MPIR’s functions API to perform arithmetic. • Use MPIR’s object-oriented API with overloaded arithmetic operators. • Time the computations in each solution. • Submit to Canvas: Assignment #6. Big Pi • Due Tuesday, March 12 • Can you compute a million digits of π? How long will it take on your computer?
A Proposed C++ Date Class • Enable programs to manipulate dates. • Example: // Construct a Date object to represent // the current date and time. Date *now = new Date(); // Print out the date such as // Tue Mar 5 09:50:10 PST 2019 cout << now->date_string() << endl;
Methods of the Date Class • Date::after() and Date::before()are convenience member functions. • Not necessary, but nice to have. • A date value is represented as a scalar value.
Points in Time Object-Oriented Design & Patterns, 2nd ed. by Cay Horstmann John Wiley & Sons, 2006.
The date_string Function • The date_string() member function of the Date class is primarily for debugging purposes. • It would be awkward to have to parse the string that it returns.
What about Month, Day, and Year? • The Date class can delegate to a Calendar class the task of converting the number of milliseconds since the epoch to year, month, day, hour, minute, and second fields. • Example Calendar classes: • GregorianCalendar • LunarCalendar • MayanCalendar • etc.
Calendar Classes • The specific Calendar class can encapsulate a changing part of an application’s design. • Make Calendar an abstract base class for the GregorianCalendar class and any other calendar classes you may write: Date Calendar Gregorian Calendar Lunar Calendar
What’s Wrong with this Code? • This code is permanently bound to the Gregorian calendar. • What if you decide later to switch to the lunar calendar? GregorianCalendar*g = new GregorianCalendar(); g->set(Calendar::YEAR, 2019); g->set(Calendar::MONTH, Calendar::MARCH); g->set(Calendar::DATE, 5);
What’s Wrong with this Code? cont’d • Instead, code to the interface. • In this case, the interface is the abstract Calendar class. • “Code to the interface” is an important design principle. • It increases flexibility. Calendar *cal= CalendarFactory::create(type); cal->set(Calendar::YEAR, 2019); cal->set(Calendar::MONTH, Calendar:: MARCH); cal->set(Calendar::DATE, 5);
A Static Factory Function Calendar *cal = CalendarFactory::create(type); cal->set(Calendar::YEAR, 2019); cal->set(Calendar::MONTH, Calendar:: MARCH); cal->set(Calendar::DATE, 5); • This code creates calendar objects with a static function in the CalendarFactory class. class CalendarFactory { public: static Calendar *create(int type) { switch (type) { case GREGORIAN: return new GregorianCalendar(); case LUNAR: return new LunarCalendar(); ... } } }
Design a Day Class • Answer questions such as • How many days between now and the end of the year? • What day is 100 days from now? • A Day object represents a particular day. • Some limitations • Uses the Gregorian calendar only • No time of day • No time zone
The Day Class • d->add_days(n)->days_from(d) equals n • Add 3 (n) days to September 11 (d) to get September 14, which is 3 days from September 11. • (d + n) - d == n • d1->add_days(d2->days_from(d1)) equals d2 • September 14 (d2) is 3 days from September 11 (d1). Add those 3 days to September 11 to get back to September 14. • d1 + (d2 - d1) == d2
The Day Class • Methods days_from() and add_days()are not trivial! • April, June, September, November have 30 days. • February has 28 days, except in leap years when it has 29 days. • All other months have 31 days. • Leap years are divisible by 4, except that after 1582, years divisible by 100 but not 400 are not leap years. • There is no year 0; year 1 is preceded by year -1. • In the switchover to the Gregorian calendar, ten days were dropped: October 15, 1582 is preceded by October 4.