Developers Heaven Forum
Desktop Programming => C/C++ & Visual C++ => Topic started by: David on March 24, 2011, 04:41:02 AM
-
Class Rational is a common student request. This may get you started ...
// rational_2.h // 2011-03-24 //
// this implementation uses 'operator overloading'
#ifndef dwRATIONAL_2_H
#define dwRATIONAL_2_H
//#include <sstream>
//#include <string>
#include <iostream>
#include <fstream>
#include <cstdlib> // re. exit ...
#include <cstdio> // re. error messages ...
#ifndef dwMYASSERT
#define dwMYASSERT
void myAssert( int condition, const char* prompt )
{
if( !condition )
{
fprintf( stderr, "Error: %s", prompt );
fputs( "\nPress 'Enter' to continue/exit ... ", stderr ); fflush( stderr );
// while( getchar() != '\n' );
getchar();
exit( 1 );
}
}
#endif
class Rational
{
public:
friend std::ostream& operator << ( std::ostream& output, const Rational& r );
friend std::istream& operator >> ( std::istream& output, Rational& r );
friend Rational operator + ( const Rational& r1, const Rational& r2 );
friend Rational operator + ( const Rational& r, long i );
friend Rational operator - ( const Rational& r1, const Rational& r2 );
friend Rational operator - ( const Rational& r, long i );
friend Rational operator * ( const Rational& r1, const Rational& r2 );
friend Rational operator * ( const Rational& r, long i );
friend Rational operator / ( const Rational& r1, const Rational& r2 );
friend Rational operator / ( const Rational& r, long i );
// default/data constructor ... reduces r immediately to its lowest terms
Rational( long n = 0, long d = 1 ) : numerator( n ), denominator( d )
{
sprintf( errMsgBUFFER, "numerator = %ld, denominator = %ld, %s",
n, d, "ctor divide by zero error" );
myAssert( (denominator != 0), errMsgBUFFER );
normalize();
}
double decimal() { return double( numerator ) / denominator; }
long get_numerator() { return numerator; }
long get_denominator() { return denominator; }
Rational operator - () const // returns a new ... newr = -r;
{ return Rational( -numerator, denominator ); }
private:
long numerator;
long denominator;
// returns the greatest common divisor (gcd) of two long's x and y
static long gcd( long x, long y )
{
if( y ) return gcd( y, x % y ); // note recursive call(s) here ...
// else
return labs( x ); // exit here from recursion when y becomes 0 above
}
void normalize()
{
if( denominator < 0 ) { denominator = -denominator; numerator = -numerator; }
long tmp_gcd = gcd( labs( numerator ), labs( denominator ));
numerator /= tmp_gcd;
denominator /= tmp_gcd;
}
// my buffer used here re. forming error messages ...
static char errMsgBUFFER[];
};
char Rational::errMsgBUFFER[128];
// friend function definitions ...
// for output << r1 << r2 << ... (in rational form)
std::ostream& operator << ( std::ostream& output, const Rational& r )
{
if( r.numerator < 0 ) output << "("<< r.numerator << ")";
else output << r.numerator;
if( r.denominator != 1 ) output << "/" << r.denominator;
return output;
}
/*
std::istream& operator >> ( std::istream& input, Rational& r )
{
for( ;; )
{
std::cout << "Enter your 'fraction' like this 3 or this 1/3: " << std::flush;
std::string line;
getline( input, line );
std::istringstream iss( line );
char c = ' '; // recall below that >> here skips over all leading whitespace
if( iss >> r.numerator ) // i.e. at least 1 good integer if this is true
{
// carry on reading stream ... in case more there ...
if( iss >> c >> r.denominator && c == '/' && r.denominator != 0 )
{ r.normalize(); return input; } // since all good ...
else if( c == ' ' ) // reached end of iss without a char input
// so only one integer was entered for data here
{
r.denominator = 1; // ensure denominator is set to 1
// don't need to call normalize() here since Fraction is
// already 'normal' since denominator value is +1 ...
return input;
}
}
// else if reach here, input data was BAD so loop again ...
if( r.denominator == 0 ) std::cout << "Divide by zero NOT defined ... ";
std::cout << "Valid input is integer or integer/integer \n";
}
}
*/
std::istream& operator >> ( std::istream& input, Rational& r )
{
char c;
input >> r.numerator >> c >> r.denominator;
if( c != '/' ) input.setstate( std::ios::badbit );
else r.normalize();
return input;
}
// for r = r1 + r2 + r3 + ... + rn;
Rational operator + (const Rational& r1, const Rational& r2 )
{ return Rational( r1.numerator * r2.denominator + r2.numerator * r1.denominator,
r1.denominator * r2.denominator ); }
Rational operator + ( const Rational& r, long i )
{ return Rational( r.numerator + r.denominator * i, r.denominator ); }
// for r = r1 - r2 - r3 ... - rn;
Rational operator - ( const Rational& r1, const Rational& r2 )
{ return Rational( r1.numerator * r2.denominator - r2.numerator * r1.denominator,
r1.denominator * r2.denominator ); }
Rational operator - ( const Rational& r, long i )
{ return Rational( r.numerator - r.denominator * i, r.denominator ); }
// for r = r1 * r2 * r3 ... * rn;
Rational operator * ( const Rational& r1, const Rational& r2 )
{ return Rational( r1.numerator * r2.numerator,
r1.denominator * r2.denominator ); }
Rational operator * ( const Rational& r, long i )
{ return Rational( r.numerator * i, r.denominator ); }
// for r = r1 / r2 / r3 ... / rn;
Rational operator / ( const Rational& r1, const Rational& r2 )
{
sprintf( Rational::errMsgBUFFER, "Rational operator / "
"( const Rational& %ld/%ld, const Rational& %ld/%ld ) %s",
r1.numerator, r1.denominator, r2.numerator, r2.denominator,
"divide by zero error" );
myAssert( (r2.denominator != 0), Rational::errMsgBUFFER );
return Rational( r1.numerator*r2.denominator, r1.denominator*r2.numerator );
}
Rational operator / ( const Rational& r, long i )
{
sprintf( Rational::errMsgBUFFER, "Rational operator / "
"( const Rational& %ld/%ld, long %ld ) %s",
r.numerator, r.denominator, i, "divide by zero error" );
myAssert( (i != 0), Rational::errMsgBUFFER );
return Rational( r.numerator, r.denominator * i );
}
#endif
-
And a test program to test the above class Rational ...
// rational_2_test.cpp // this version 2011-03-24 //
// this file is supplied to test out rational_2.h
#define OUTFILE "rational_2.txt" // output goes to file rational_2.txt
//#include <iomanip>
#include "datetime.h" // class datetime includes ...
// <iostream>, <iomanip>, <sstream>,
// <string>, <ctime>, <cctype>
#include "rational_2.h" // class Rational includes ...
// <iostream>, <fstream>, <cstdlib>, ctdio>
int main()
{
using std::ofstream;
using std::cout;
using std::cin;
using std::endl;
using std::flush;
using std::fixed;
using std::setprecision;
Rational r0, r1(-1), r2(2,3), r3(-3,4), r4(4,6), r5(5,-6), r6(60,-18),
r7(7,8), r8(8,9), r9(10,9);
ofstream fout( OUTFILE );
datetime dt; // ctor date and time right now ...
fout << fixed << setprecision(4)
<< "ORIGINAL DATA tested: " << dt.get_date()
<< " :: " << dt.get_time() << " ..."
<< endl << "r0 = " << r0 << " = " << r0.decimal()
<< endl << "r1 = " << r1 << " = " << r1.decimal()
<< endl << "r2 = " << r2 << " = " << r2.decimal()
<< endl << "r3 = " << r3 << " = " << r3.decimal()
<< endl << "r4 = " << r4 << " = " << r4.decimal()
<< endl << "r5 = " << r5 << " = " << r5.decimal()
<< endl << "r6 = " << r6 << " = " << r6.decimal()
<< endl << "r7 = " << r7 << " = " << r7.decimal()
<< endl << "r8 = " << r8 << " = " << r8.decimal()
<< endl << "r9 = " << r9 << " = " << r9.decimal()
<< "\n\nCALCULATIONS ..."
<< endl << "r2 + r3 = " << r2 + r3
<< endl << "r4 - r5 = " << r4 - r5
<< endl << "r6 * r7 = " << r6 * r7
<< endl << "r8 / r9 = " << r8 / r9
<< endl << "(r2+r3)/((r4-r5)*r6*r7) = " << ((r2+r3)/((r4-r5)*r6*r7))
<< " = " << ((r2+r3)/((r4-r5)*r6*r7)).decimal()
<< endl << "r2 + 5 = " << r2 + 5 << " and 5 + r2 = " << 5 + r2
<< endl << "r2 - 5 = " << r2 - 5 << " and 5 - r2 = " << 5 - r2
<< endl << "r2 * 5 = " << r2 * 5 << " and 5 * r2 = " << 5 * r2
<< endl << "r2 / 5 = " << r2 / 5 << " and 5 / r2 = " << 5 / r2
//<< endl << "r0 / 5 = " << r0 / 5
//<< " and 5 / r0 = " << 5 / r0 // test myAssert
//<< " and r0 / 0 = " << r0 / 0 // test myAssert
<< endl << "-r2 = " << -r2 << " and -1 / (1 / -r2) = " << -1 / (1 / -r2)
<< endl ;
// Now get 3 Fractions from keyboard entry ... and output results to file
Rational x[3];
cout << "Enter Fractions like this 7/11 ...\n";
for( int i = 0; i < 3; )
{
cout << "Enter fraction " << i+1 << " : " << flush;
if( cin >> x[i] ) ++i;
else
{
cout << "Data entry error ... "
<< "integer fractions like 11/7 only please.\n";
cin.clear();
}
cin.sync();
}
fout << x[0] << "*" << x[1] << "-" << x[2] << " = "
<< x[0] * x[1] - x[2] << endl;
fout.close();
// if you have a Windows OS ... see OUTFILE with ...
system( "notepad " OUTFILE ) ;
}
-
And here is the include file for class datetime ... (used in the above program that tests class Rational) ...
// datetime.h
#ifndef dwDATETIME_H
#define dwDATETIME_H
/*
For BEGINNING COMPUTER PROGRAMMING using HLA, Python, C/C++, goto ...
http://developers-heaven.net/forum/index.php/topic,46.0.html
*/
#include <iostream>
#include <iomanip> // setw, setfill
#include <sstream>
#include <string>
#include <ctime>
#include <cctype> // toupper
//using namespace std;
class datetime
{
public:
datetime() // default constructor to fill up private time data 'right now'
{
char c;
time_t now = time( 0 );
std::istringstream iss( ctime( &now ) ); // "Fri Nov 27 16:22:24 2009"
std::string weekdayStr, monthStr;
iss >> weekdayStr >> monthStr >> day
>> hour >> c >> minute >> c >> second // using char 'c' to skip ':'
>> year;
weekday = find_weekday( weekdayStr );
month = find_month( monthStr );
}
std::string get_date()
{
std::ostringstream oss;
oss << year << "-" << std::setfill('0') << std::setw(2) << (month+1) << "-"
<< std::setw(2) << day << std::setfill(' ');
return oss.str();
}
std::string get_time()
{
std::ostringstream oss;
oss << std::setfill('0') << std::setw(2) << hour << ":"
<< std::setw(2) << minute << ":"
<< std::setw(2) << second << std::setfill(' ');
return oss.str();
}
std::string get_datetime() { return get_date() + " " + get_time(); }
std::string get_weekdayname() { return daysTable[ weekday ]; }
std::string get_weekdaynameL() { return daysTable[ weekday+14 ]; }
std::string get_weekdaynumber() { return daysTable[ weekday+7 ]; } //1st,2nd...7th
std::string get_monthname() { return monthsTable[ month ]; }
std::string get_monthnameL() { return monthsTable[ month+24 ]; }
std::string get_monthnumber01() { return monthsTable[ month+12 ]; }
std::string get_monthnumber() { return monthsTable[ month+36 ]; } //1st,2nd...12th
std::string get_monthdaynumber() { return dayOfMonthTable[ day-1 ]; }//1st,2nd...31st
int get_year() { return year; }
int get_month() { return month + 1; }
int get_day() { return day; }
int get_weekday() { return weekday + 1; }
int get_hour() { return hour; }
int get_minute() { return minute; }
int get_second() { return second; }
private:
int year;
int month; // 0..11
int day; // 1..31
int weekday; // 0..6
int hour; // 0..23
int minute; // 0..59
int second; // 0..59
static const std::string monthsTable[];
static const std::string daysTable[];
static const std::string dayOfMonthTable[];
static int find_weekday( std::string wdStr )
{
for( int n = 0; n < 7; ++n )
if( daysTable[n] == wdStr ) return n; // 0..6
// else if error ... handle ... but for now ... out of bounds error
return 7;
}
static int find_month( std::string mStr )
{
for( int n = 0; n < 12; ++n )
if( monthsTable[n] == mStr ) return n; // 0..11
// else if error ... handle ... but for now ... out of bounds error
return 12;
}
};
// define your (language) static const arrays here ... (after def'n above)
const std::string datetime::daysTable[] =
{
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
"1st", "2nd", "3rd", "4th", "5th", "6th", "7th",
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday"
};
const std::string datetime::monthsTable[] =
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
"01", "02", "03", "04", "05", "06",
"07", "08", "09", "10", "11", "12",
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December",
"1st", "2nd", "3rd", "4th", "5th", "6th",
"7th", "8th", "9th", "10th", "11th", "12th"
};
const std::string datetime::dayOfMonthTable[] =
{
"1st", "2nd", "3rd", "4th", "5th", "6th",
"7th", "8th", "9th", "10th", "11th", "12th",
"13th", "14th", "15th", "16th", "17th", "18th",
"19th", "20th", "21st", "22nd", "23rd", "24th",
"25th", "26th", "27th", "28th", "29th", "30th", "31st"
};
#ifndef dwTOALLCAPS_H
#define dwTOALLCAPS_H
// utility function used here ...
std::string toAllCaps( std::string inStr ) // make a local copy of string passed in
{
for( int i = inStr.size()-1; i >= 0; --i ) inStr[i] = toupper( inStr[i] );
return inStr;
}
#endif
#endif