Author Topic: class Rational ... a start ... with a test program that uses class datetime  (Read 5869 times)

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Class Rational is a common student request.  This may get you started ...

Code: [Select]
// 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

« Last Edit: March 25, 2011, 01:54:29 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: class Rational ... a start
« Reply #1 on: March 25, 2011, 01:33:46 AM »
And a test program to test the above class Rational ...

Code: [Select]
// 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 ) ;
}

« Last Edit: March 25, 2011, 03:31:34 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: class Rational ... a start
« Reply #2 on: March 25, 2011, 01:48:58 AM »
And here is the include file for class datetime ... (used in the above program that tests class Rational) ...

Code: [Select]
// 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

« Last Edit: March 25, 2011, 02:29:45 AM by David »