Code: Select all
/* Fraction Calculator
Author: Chris Kee
March 28, 2009
*/
#include <iostream>
#include <string>
#include <cmath>
#include <iomanip>
#include <fstream>
using namespace std;
enum operation { PLUS , MINUS , MULT , DIV };
struct fraction
{
int numer;
int denom;
};
void drawScreen( fraction x , fraction y , fraction z , operation n );
int noOfDigs( int x );
void makeSpace( int x );
void handleInput( istream& cin , fraction& x , fraction& y , fraction& z , operation& n , bool& quit );
void solveFraction( fraction& x , fraction& y , fraction& z , operation n );
void lcd( fraction& x );
int main()
{
fraction num1 = { 0 , 1 };
fraction num2 = { 0 , 1 };
fraction answ = { 0 , 1 };
operation oper = PLUS;
bool quit = false;
while( !quit )
{
system("cls");
drawScreen( num1 , num2 , answ , oper );
handleInput( cin , num1 , num2 , answ , oper , quit );
}
}
void drawScreen( fraction x , fraction y , fraction z , operation n )
{
//int variable to hold number of spaces we need;
int sp = 0;
cout << endl;
if( ( x.denom == 0 ) || ( y.denom == 0 ) || ( z.denom == 0 ) )
{
cout << "\t\tERROR: Undefined Results! Denominator Cannot Be Zero";
}
cout << endl;
//Draw top border
for( int i = 0 ; i < 80 ; i++ )
cout << '~';
cout << endl << endl;
//First fraction holds 10 horizontal spaces, the operator holds 5, 1 space buffer in between things.
//**************************************** DRAW THE NUMERATORS ****************************************************
//Make 15 spaces ( margin )
makeSpace( 15 );
//Width of numerators is 10, we will append spaces to the end until the number is centered.
sp = noOfDigs( x.numer );
cout << setw( 5 + ( sp / 2 ) ) << x.numer;
makeSpace( 10 - ( 5 + ( sp / 2 ) ) );
//Room to the next Numerator. There will be, this is where the operator will be, but we're above that now.
makeSpace( 7 );
//Width of numerators is 10, we will append spaces to the end until the number is centered.
sp = noOfDigs( y.numer );
cout << setw( 5 + ( sp / 2 ) ) << y.numer;
makeSpace( 10 - ( 5 + ( sp / 2 ) ) );
//Room to the next Numerator. There will be, this is where the operator will be, but we're above that now.
makeSpace( 7 );
//Width of numerators is 10, we will append spaces to the end until the number is centered.
sp = noOfDigs( z.numer );
cout << setw( 5 + ( sp / 2 ) ) << z.numer;
makeSpace( 10 - ( 5 + ( sp / 2 ) ) );
//Skip two spaces, ease of reading;
cout << endl << endl;
//************************** NEXT SECTION BUILDS OPERATORS AND DIVISION LINES!!! **********************************
//margin
makeSpace( 14 );
//Draw x's division line
for( int i = 0 ; i < 10 ; i++ )
cout << '=';
//Draw the operator
if( n == PLUS )
{
cout << " + ";
}else if( n == MINUS )
{
cout << " - ";
}else if( n == MULT )
{
cout << " * ";
}else if( n == DIV )
{
cout << " / ";
}
//Draw y's division line
for( int i = 0 ; i < 10 ; i++ )
cout << '=';
//Draw equal sign
cout << " = ";
//Draw z's division line
for( int i = 0 ; i < 10 ; i++ )
cout << '=';
//Skip two spaces for ease of reading
cout << endl << endl;
//********************************** DRAW THE DENOMINATORS *******************************************************
//Make 15 spaces ( margin )
makeSpace( 15 );
//Width of denominators is 10, we will append spaces to the end until the number is centered.
sp = noOfDigs( x.denom );
cout << setw( 5 + ( sp / 2 ) ) << x.denom;
makeSpace( 10 - ( 5 + ( sp / 2 ) ) );
//Room to the next denomator. There will be, this is where the operator will be, but we're above that now.
makeSpace( 7 );
//Width of denominators is 10, we will append spaces to the end until the number is centered.
sp = noOfDigs( y.denom );
cout << setw( 5 + ( sp / 2 ) ) << y.denom;
makeSpace( 10 - ( 5 + ( sp / 2 ) ) );
//Room to the next denominator. There will be, this is where the operator will be, but we're above that now.
makeSpace( 7 );
//Width of denomators is 10, we will append spaces to the end until the number is centered.
sp = noOfDigs( z.denom );
cout << setw( 5 + ( sp / 2 ) ) << z.denom;
makeSpace( 10 - ( 5 + ( sp / 2 ) ) );
//Skip two spaces, ease of reading;
cout << endl << endl;
//Draw bottom border
cout << endl << endl;
for( int i = 0 ; i < 80 ; i++ )
cout << '~';
}
int noOfDigs( int x )
{
//This function takes in an integer, and returns the number of digits that integer has.
//IE: the integer 6453 has 4 digits, so noOfDigs( 6453 ) returns 4.
int digs = 0;
for( int i = 0 ; pow( 10.0 , static_cast<double>( i ) ) < x ; i++ )
{
digs = i;
}
return digs;
}
void makeSpace( int x )
{
for( int i = 0 ; i < x ; i++ )
cout << ' ';
}
void handleInput( istream& cin , fraction& x , fraction& y , fraction& z , operation& n , bool& quit )
{
/*
This function both creates a menu and takes input from the user. The input it takes usually a number
we can use to navigate the menu. It will also prompt the user for an integer when appropriate. IE To
use as a numerator or a denominator for the selecte fraction
*/
//Variable used to take input into the menu so we can navigate.
int input = 0;
//This static variable keeps track of where we are in the menu.
static int loc = 0;
//Instructional
cout << endl << "\tPlease Enter An Option" << endl << endl;
//Build the Main menu
if( loc == 0 )
{
cout << "\t1: Enter a Numerator\t2: Enter a Denominator\n\t3: Choose Operation\t4: Solve\n\t5: Quit" << endl << endl;
}
//Build Numerator Menu
if( loc == 1 )
{
cout << "\t1: Enter numerator for fraction A\n\t2: Enter numerator for fraction B\n\t3: Back" << endl << endl;
}
//Build Denominator Menu
if( loc == 2 )
{
cout << "\t1: Enter denominator for fraction A\n\t2: Enter denominator for fraction B\n\t3: Back" << endl << endl;
}
//Build Choose Operation Menu
if( loc == 3 )
{
cout << "\t1: Addition\t\t2: Subtraction\n\t3: Multiplication\t4: Division\n\t5: Back" << endl << endl;
}
cout << "\n\t:";
cin >> input;
if( !cin )
{
cin.clear();
cin.ignore( 1000 , '\n' );
}
if( loc == 0 )
{
switch( input )
{
case 1:
loc = 1;
break;
case 2:
loc = 2;
break;
case 3:
loc = 3;
break;
case 4:
solveFraction( x , y , z , n );
break;
case 5:
quit = true;
break;
default:
loc = 0;
}
}else if( loc == 1 )
{
switch( input )
{
case 1:
cout << "Enter a value: ";
cin >> x.numer;
loc = 0;
break;
case 2:
cout << "Enter a value: ";
cin >> y.numer;
loc = 0;
break;
case 3:
loc = 0;
break;
default:
loc = 1;
}
}else if( loc == 2 )
{
switch( input )
{
case 1:
cout << "Enter a value: ";
cin >> x.denom;
loc = 0;
break;
case 2:
cout << "Enter a value: ";
cin >> y.denom;
loc = 0;
break;
case 3:
loc = 0;
break;
default:
loc = 2;
}
}else if( loc == 3 )
{
switch( input )
{
case 1:
n = PLUS;
loc = 0;
break;
case 2:
n = MINUS;
loc = 0;
break;
case 3:
n = MULT;
loc = 0;
break;
case 4:
n = DIV;
loc = 0;
break;
case 5:
loc = 0;
break;
default:
loc = 3;
}
}
}
void solveFraction( fraction& x , fraction& y , fraction& z , operation n )
{
//This function takes as input, three fractions and an operation. It performs the selected operation
//on x and y, and stores the result in z.
//All fraction parameters are taken as references so they may be passed to the LCD function.
//First we need to know what type of operation we are performing. That is the first if else switch series
//Make an output txt, I was using this to debug some problems with the math.
//ofstream fout;
//fout.open( "math.txt" , fstream::app );
if( n == PLUS )
{
//fout << "\nPLUS:" << endl;
//If the two fractions do not have the same denominator
if( x.denom != y.denom )
{
int xden = x.denom;
int yden = y.denom;
//Multiply each fraction by the other term's denominator, this will give both fractions the same denominator
x.denom *= yden;
//fout << "x.denom *= y.denom; //" << x.denom << " " << y.denom << endl;
x.numer *= yden;
//fout << "x.numer *= y.denom; //" << x.numer << " " << y.denom << endl;
y.denom *= xden;
//fout << "y.denom *= x.denom; //" << y.denom << " " << x.denom << endl;
y.numer *= xden;
//fout << "y.numer *= x.denom; //" << y.numer << " " << x.denom << endl;
}
//Now add the numerators and preserve the common denominator.
//fout << x.numer << "/" << x.denom << " + " << y.numer << "/" << y.denom << " = ";
z.numer = x.numer + y.numer;
z.denom = x.denom;
//fout << z.numer << "/" << z.denom << endl;
}else if( n == MINUS )
{
//Repeat the addition logic for subtraction.
//fout << "\nMINUS:" << endl;
//If the two fractions do not have the same denominator
if( x.denom != y.denom )
{
int xden = x.denom;
int yden = y.denom;
//Multiply each fraction by the other term's denominator, this will give both fractions the same denominator
x.denom *= yden;
//fout << "x.denom *= y.denom; //" << x.denom << " " << y.denom << endl;
x.numer *= yden;
//fout << "x.numer *= y.denom; //" << x.numer << " " << y.denom << endl;
y.denom *= xden;
//fout << "y.denom *= x.denom; //" << y.denom << " " << x.denom << endl;
y.numer *= xden;
//fout << "y.numer *= x.denom; //" << y.numer << " " << x.denom << endl;
}
//Now add the numerators and preserve the common denominator.
//fout << x.numer << "/" << x.denom << " - " << y.numer << "/" << y.denom << " = ";
z.numer = x.numer - y.numer;
z.denom = x.denom;
//fout << z.numer << "/" << z.denom << endl;
}else if( n == MULT )
{
//For multiplication, we simply multiply the numerators and denominators
z.numer = x.numer * y.numer;
z.denom = x.denom * y.denom;
}else if( n == DIV )
{
//fout << "/nDIVISION" << endl;
//For division, we multiply x by the inverse of y
z.numer = x.numer * y.denom;
//fout << "z.numer = x.numer * y.denom; //" << z.numer << x.numer << y.denom << endl;
z.denom = x.denom * y.numer;
//fout << "z.denom = x.numer * y.numer; //" << z.denom << x.numer << y.denom << endl;
}
//Put all fractions in simplest terms
lcd( x );
lcd( y );
lcd( z );
}
void lcd( fraction& x )
{
//This function takes the parameter fraction and puts in simplest terms.
//And integer to hold our largest common factor.
int y = 1;
//Find the factors of the numerator
for( int i = 2 ; i <= x.numer ; i++ )
{
//If the numerator is evenly divisible by i
if( x.numer % i == 0 )
{
//Check to see if it is also divisible by the denominator
if( x.denom % i == 0 )
{
//If it is our largest common factor so far
if( i >= y )
{
//Store it in a variable
y = i;
}
}
}
}
//Devide the fraction by the largest common factor
x.numer /= y;
x.denom /= y;
//If both sides of the division bar are negative, the fraction is positive.
if( ( x.numer < 0 ) && ( x.denom < 0 ) )
{
x.numer = -x.numer;
x.denom = -x.denom;
}
//If the fraction IS negative, make sure the negative sign is on the numerator
if( ( x.numer > 0 ) && ( x.denom < 0 ) )
{
x.numer = -x.numer;
x.denom = -x.denom;
}
}