/*
description: This is a calculator that performs +, -, *, / and $ (exponent) on hexadecimal operands.
*/
#include <iostream>
#include <fstream>
#include <string>
#include <stdlib.h>
using namespace std;
//Function declarations
void doMath(string op1, string op2, char oper, string opString);
string add (string op1, string op2);
string sub (string op1, string op2);
string mul (string op1, string op2);
string div (string op1, string op2);
string exp (string op1, string op2);
int hexToInt(string hex);
int CtoI (char ch);
char ItoC (int x);
//-------------------------------------------------------------------------------------------------
int main ()
{
ifstream in; //Declare fstream to hold string from file
string opString, op1, op2, prompt = "Please enter the name of the file you would like to open (max 300 characters): ";
char file[300];
char oper;
bool op1b = false, operb = false;
unsigned int i = 0;
cout << prompt << endl; //Prompt user
cin >> file; //Read in file
in.open(file);
//Check if it exists
if (!in) {
cout << "Error. File not found.";
return 1;
}
while (!in.eof())
{
op1.clear();
op2.clear();
op1b = operb = false;
opString.clear();
in >> opString; //Read in string from file
//Read the string from file character by character
for (i = 0; i < opString.size(); i++)
{
if (!op1b) //If we do not yet know our first operand (op1b = false, b stands for bool, clever naming eh?)
{ //Check if our next item is an operator. If it is...
if (!(opString[i] == '+' || opString[i] == '-' || opString[i] == '*' || opString[i] == '/' || opString[i] == '$'))
op1.push_back(opString[i]);
else //... when we hit an symbol, our first number is known; do not repeat this if-statement block
op1b = true;
}
if (op1b && !operb) //If we know our first operand but not our operator...
{
oper = opString[i]; //Find out what our operator is. Now we know it (operb = true)
operb = true;
i++; //We increment i because if we did not we'd double dip on the if statement below and wind up
} // with an operator tacked onto the beginning of the second operand
if (op1b && operb) //If we know our first operand and the operation, let's find operand #2
{
if (opString[i] == '=') //If we have an =, we know all our info. Proceed to operation.
break;
else
{
op2.push_back(opString[i]); //Add to op2.
}
}
}
if (op1.size() <= 40 || op2.size() <= 40) //Max operator size is 40
doMath(op1,op2,oper, opString);
else
cout << "Operand too large.\n";
}
return 0;
}
//-------------------------------------------------------------------------------------------------
void doMath(string op1, string op2, char oper, string opString)
{
string ans;
switch (oper) //Determine what to do.
{
case '+': //Addition
ans = add(op1,op2);
break;
case '-':
ans = sub(op1,op2);
break;
case '*':
ans = mul(op1,op2);
break;
case '/':
ans = div(op1,op2);
break;
case '$':
ans = exp(op1,op2);
break;
}
opString.append(ans);
cout << opString << endl; //Display final answer
}
//-------------------------------------------------------------------------------------------------
string add (string op1, string op2)
{
string result;
string carry;
int length1 = op1.size(), length2 = op2.size();
int i, num, sum, m, c = 0, j, k;
string str;
char chr[1];
//Make equal size
if (length2 > length1) //Make each operand have equal number of digits; add leading 0s
{
num = length2 - length1;
for (i = 0; i < num; i++)
str.push_back('0');
op1.insert(0,str);
}
else if (length1 > length2) //Make each operand have equal number of digits; add leading 0s
{
num = length1 - length2;
for (i = 0; i < num; i++)
str.push_back('0');
op2.insert(0,str);
}
//cout << endl << "OP1 AFTER: " << op1 << endl << "OP2 AFTER: " << op2 << endl << endl;
//Do the work of adding
for (i = op1.size()-1; i >= 0; i--)
{
j = k = 0;
//Convert char to int
j = (CtoI(op1[i]));
k = (CtoI(op2[i]));
//cout << endl << "Op 1 at pos i (j): " << j << " Op 2 at pos i (k): " << k << endl << endl;
sum = j + k + c;
carry.clear();
c = 0;
if (sum >= 10)
{
if (sum > 15 && sum < 26) //Value is in between 10 and 19 (hex), so assign appropriate digit to result
{
sum -= 16;
m = sprintf(chr, "%u", sum);
result.insert(0,chr);
c = 1;
carry.push_back('1');
}
if (sum >= 26) //Value is greater than hex 19, (but implicitly less than hex 20/dec 31), so push a carry then
{ // proceed to swith statement below. Decrement 16 in order to reuse same cases as before.
sum -= 16;
carry.push_back('1');
c = 1;
}
switch (sum) //Long a$$ switch statement
{
case 10: //When our decimal sum = 10-15 (or 26-31; hex A-F or 1A-1F), we need to replace the decimal
result.insert(0,"A"); // representations of those numbers with their hexadecimal representation (A-F).
break;
case 11:
result.insert(0,"B");
break;
case 12:
result.insert(0,"C");
break;
case 13:
result.insert(0,"D");
break;
case 14:
result.insert(0,"E");
break;
case 15:
result.insert(0,"F");
break;
}
}
else
{
m = sprintf(chr, "%u", sum);
result.insert(0, chr);
}
}
if (c != 0) //If we have left over carry
{
m = sprintf(chr, "%u", c);
result.insert(0, chr);
}
//cout << " FINAL RESULT: " << result << endl << endl;
return result;
}
//-------------------------------------------------------------------------------------------------
string sub (string op1, string op2)
{
string result;
string borrow;
int length1 = op1.size(), length2 = op2.size();
int i, num, difference, m, b = 0, j, k;
string str;
char chr[1];
/*Immediately check if our second operand is greater than our first. If it is, we do not do the calculation (this is mostly for division)
since we are not anticipating bad input for subtraction alone. This will NOT verify if there are leading 0s. */
//If we try to subtract a larger number, we can't; go back.
if (length2 > length1)
return op1;
else if (length1 == length2)
{
for (i = 0; i < length1; i++) //Test each value in the string
{
//Convert char to int
j = (CtoI(op1[i])); //Op1
k = (CtoI(op2[i])); //Op2
//Return op1 if too big
if (j > k)
break;
if (j < k)
return op1;
}
}
if (length1 > length2) //Make each operand have equal number of digits; add leading 0s
{
num = length1 - length2;
for (i = 0; i < num; i++)
str.push_back('0');
op2.insert(0,str);
}
for (i = op1.size()-1; i >= 0; i--)
{
j = k = 0;
//Convert char to int
j = (CtoI(op1[i])); //Op1
k = (CtoI(op2[i])); //Op2
//cout << endl << "Op 1 at pos i (j): " << j << " Op 2 at pos i (k): " << k << endl << endl;
if (k <= j) //Make sure second number is less than or equal to the first one; if not, we borrow later.
{
difference = j - k; // difference = op1 - op2
if (difference >= 10) //If our difference is >10, store our result as hex
{
switch (difference)
{
case 15:
result.insert(0,"F");
break;
case 14:
result.insert(0,"E");
break;
case 13:
result.insert(0,"D");
break;
case 12:
result.insert(0,"C");
break;
case 11:
result.insert(0,"B");
break;
case 10:
result.insert(0,"A");
break;
}
}
else
{
m = sprintf(chr, "%u", difference);
result.insert(0, chr);
}
}
else if (k > j) //If our second number's current place is greater than our first, we need to borrow
{
str.clear();
str += op1[i];
str.insert(0,"1"); //We will always add 16 dec (10 hex) to the first bit, so pin a "1" to the front of it
//cout << "NEW BORROWED BIT: " << str << endl << endl;
//Make sure we decrement 1 from next place value...
if (i > 0) //Make sure we do not get the index out of bounds
b = i-1; //Get index for next left value
while (b >= 0) //We need to decrement 1 from the column we borrow from. If we cannot borrow, continue down the line until
{ // we find one we can borrow from, updating each column as necessary.
if (op1[b] != '0') //If we need to borrow, make sure it's not 0
{
m = CtoI(op1[b]); //Retrieve value in that spot
m -= 1; //Decrement that place value by 1 since borrowing
chr[0] = ItoC(m); //Convert back to char
op1[b] = chr[0]; //Replace place with new decremented value
break; //Exit loop; we're done borrowing.
}
else if (op1[b] == '0') //If we cannot borrow from here (since the place is 0), change its value to 'F' and continue down
{ // until we find a value we can borrow from.
op1[b] = 'F';
b--;
}
}
//Perform actual subtraction with new adjusted/borrowed values
j = hexToInt(str); //Convert to hex
k = (CtoI(op2[i]));
difference = j - k; //Difference = op1 (after borrow) - op2;
if (difference >= 10) //If our difference is >10, store our result as hex
{
switch (difference)
{
case 15:
result.insert(0,"F");
break;
case 14:
result.insert(0,"E");
break;
case 13:
result.insert(0,"D");
break;
case 12:
result.insert(0,"C");
break;
case 11:
result.insert(0,"B");
break;
case 10:
result.insert(0,"A");
break;
}
}
else
{
m = sprintf(chr, "%u", difference);
result.insert(0, chr);
}
}
}
//Truncate extra leading 0s if applicable
//Check our result size, too. Make sure we don't erase our only 0 in case we have op1 = op2 and then op1-op2!
while (result[0] == '0' && result.size() > 1) //If first spot == 0
result.erase(0,1); // erase it (erase between index 0 and index 1)
return result;
}
//-------------------------------------------------------------------------------------------------
string mul (string op1, string op2)
{
string count, result, str;
/* * is a shortcut for + for lots of the same operand. For example, 4*3 is a different way of writing 4+4+4 or 3+3+3+3. We just need to
add x to itself y many times in the expression x*y. */
result.clear(); //Result starts at 0. This will cumulatively grow with the successive additions of the number in question.
while ("0" != op2) {
result = add(result,op1);
op2 = sub(op2,"1");
}
return result;
}
//-------------------------------------------------------------------------------------------------
string div (string op1, string op2)
{
string result, str, count, last;
int m;
char chr[1];
/* / is a shortcut for - for lots of the same operand until we hit 0. For example, 12/3 is a different way of writing 12-3-3-3-3. We
just need to subtract y from x until we hit 0. We may or may not have a remainder. */
result = op1;
count = "0";
while (true)
{
last = result;
result = sub(result, op2);
if (result == last)
break;
else
count = add(count, "1");
}
m = hexToInt(result);
switch (m)
{
case 15:
result.clear();
result.assign("F");
break;
case 14:
result.clear();
result.assign("E");
break;
case 13:
result.clear();
result.assign("D");
break;
case 12:
result.clear();
result.assign("C");
break;
case 11:
result.clear();
result.assign("B");
break;
case 10:
result.clear();
result.assign("A");
break;
}
str = "Quotient " + count + ", Remainder " + result;
return str;
}
//-------------------------------------------------------------------------------------------------
string exp(string op1, string op2)
{
string result, temp, count;
temp.assign("0");
result.assign("1");
while ("0" != op2) {
result = mul(result,op1);
op2 = sub(op2,"1");
}
return result;
}
//Convert chars to ints
int CtoI (char ch)
{
int result;
//0 - 9
if ((int) ch > 47 && (int) ch < 58)
{
return(int (ch) - 48);
}
//A - F
else if ((int) ch > 64 && (int) ch < 71)
{
return(int (ch) - 55);
}
return result;
}
//-------------------------------------------------------------------------------------------------
//Convert int to char
char ItoC (int x)
{
//0-9
char result;
if (x >= 0 && x < 10)
{
result = char (x + 48);
}
//10-15
else if (x >= 10 && x < 16)
{
result = char (x + 55);
}
}
//works for 2 digit hex nums only
int hexToInt(string hex)
{
int x, y, z;
for (int i = 0; i < hex.size(); i++)
{
if (i == 0)
{
x = CtoI(hex[i]);
x *= 16;
}
if (i == 1)
y = CtoI(hex[i]);
}
z = x + y;
return z;
}