How Would You Write A Dynamic Text Input Calculator?

Started by
23 comments, last by ajm113 12 years ago
how any of you would write a dynamic text input calculator.[/quote]

<script type="text/javascript">
document.write(eval('2+2'));
</script>
Advertisement
Telastyn, can that program parse "-(5)" as an expression? I think you might have made the same mistake I initially made and forgot to implement unary operators.
Not a mistake, an omission wink.png

Not a mistake, an omission wink.png

biggrin.png

Not a mistake, an omission wink.png

It's not a bug! It's a feature!

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Thanks for the tips and information guys. I've made my own which works. (Crashes if you have a syntax error. Such as missing right hand operations.) But otherwise it works perfectly fine, I'm still going to fix it up and add more error handling, but if any of you are interested. I used the basic vector list approach instead of binary trees.

I'll have to put your code to the test alvaro and see who's runs better. ;) Mine is more code, but I think it makes it a little more robust.

mathNode.h


#ifndef MATH_NODE_H
#define MATH_NODE_H

enum MATH_TYPE {
NUMBER = 0,
OPERATOR,
SUB
};


struct mathNode
{
MATH_TYPE m_Type;
double m_dValue;
char m_Op;

std::vector<mathNode> sub;

mathNode()
{
m_Type = SUB;
m_dValue = 0;
m_Op = NULL;
}

mathNode(char op)
{
m_Type = OPERATOR;
m_dValue = 0;
m_Op = op;
sub.reserve(0);
}

mathNode(double m_dValue)
{
m_Type = NUMBER;
m_dValue = m_dValue;
m_Op = NULL;
sub.reserve(0);
}



};


class MathArray
{
public:
MathArray(void);

size_t npos();

void AddElement(double val, size_t i_sub = -1);
void AddElement(char op, size_t i_sub = -1);

size_t AddElementSub();


size_t size();
size_t subs_count();

size_t sub_size(size_t id);


size_t find_first_sub(size_t index = 0);
size_t find_last_sub(size_t index = 0);
size_t find_sub(size_t id);

std::vector<mathNode> getVector();


void clear();

protected:
private:

size_t sub_count;
std::vector<mathNode> root;

};


#endif



mathNode.cpp


#include "stdafx.h"
#include "mathNode.h"


MathArray::MathArray()
{
sub_count = 0;
}

size_t MathArray::npos()
{
return -1;
}


void MathArray::AddElement(char op, size_t i_sub)
{

if(i_sub == npos())
{
mathNode node(op);
root.push_back(node);

return;
}

if(i_sub >= 0 && i_sub < root.size())
{
mathNode node(op);
root.at(i_sub).sub.push_back(node);
}
}


void MathArray::AddElement(double val, size_t i_sub)
{
if(i_sub == npos())
{
mathNode node = mathNode(val);
node.m_dValue = val;
root.push_back(node);

return;
}

if(i_sub >= 0 && i_sub < root.size())
{
mathNode node(val);
node.m_dValue = val;
root.at(i_sub).sub.push_back(node);
}
}

size_t MathArray::AddElementSub()
{
mathNode node;
root.push_back(node);
sub_count++;

return (root.size()-1);
}

void MathArray::clear()
{

sub_count = 0;
for(size_t i = 0; i<root.size(); i++)
{
if(root.at(i).m_Type == SUB)
{
root.at(i).sub.clear();
}
}

root.clear();

}

size_t MathArray::size()
{
return root.size();
}

size_t MathArray::find_first_sub(size_t index)
{

if(index <= npos())
{
index = 0;
}

for(size_t i = index; i<root.size(); i++)
{
if(root.at(i).m_Type == SUB)
{
return i;
}
}

return npos();

}

size_t MathArray::find_last_sub(size_t index)
{
if(index <= npos())
{
index = 0;
}

for(size_t i = index; i>0; i--)
{
if(root.at(i).m_Type == SUB)
{
return i;
}
}

return npos();
}

size_t MathArray::find_sub(size_t id)
{
for(size_t i = 0; i<root.size(); i++)
{
if(root.at(i).m_Type == SUB)
{
return i;
}
}

return npos();
}

size_t MathArray::sub_size(size_t id)
{
if(id < 0 || id >= root.size())
{
return npos();
}

return root.at(id).sub.size();
}

size_t MathArray::subs_count()
{
return sub_count;
}

std::vector<mathNode> MathArray::getVector()
{
return root;
}



Calculator.cpp


#include "StdAfx.h"
#include "Calculator.h"

Calculator::Calculator(void)
{

}


bool Calculator::CanBeUsedInCalculator(std::string line)
{

for(size_t i = 0; i<line.size(); i++)
{

if(line >= 40 && line <= 43 || line == 32)
{
continue;
}

if(line >= 45 && line <= 57)
{
continue;
}

return false;

}


return true;
}

double Calculator::CalculateValue(std::string line)
{

line += ' ';
std::string tempValue = "";
bool AddNumber = false;
bool InBraces = false;
size_t sub_index = m_MathRoot.npos();
for(size_t i = 0; i<line.size(); i++)
{

bool IsMinus = false;
if(line == 45)
{
if(m_MathRoot.getVector().at(m_MathRoot.size()-1).m_Type != OPERATOR)
{
IsMinus = true;
}
}

if(line >= 48 && line <= 57 || line == 46 || (line == 45 && !IsMinus))
{
AddNumber = true;
tempValue += line;
continue;
}

if(AddNumber)
{
if(line == ' ' || line == '(' || line == ')' ||
line == '-' || line == '+' || line == '*' || line == '/')
{
AddNumber = false;
double d_val = atof(tempValue.c_str());
m_MathRoot.AddElement(d_val, sub_index);
tempValue = "";
}

}

if(line == '(' && !InBraces)
{
InBraces = true;
sub_index = m_MathRoot.AddElementSub();
continue;
}else if(line == ')' && InBraces){
InBraces = false;
sub_index = m_MathRoot.npos();
}

switch(line)
{
case '+':
m_MathRoot.AddElement('+', sub_index);
break;

case '-':
m_MathRoot.AddElement('-', sub_index);
break;

case '*':
m_MathRoot.AddElement('*', sub_index);
break;

case '/':
m_MathRoot.AddElement('/', sub_index);
break;
}

continue;

}

//After compiling, calculate the results!
double result = 0;
double last_result = m_MathRoot.getVector().at(0).m_dValue;

for(size_t i = 1; i<m_MathRoot.size(); i += 2)
{

if(i+1 >= m_MathRoot.size())
{
printf("Syntax Error!\n");
m_MathRoot.clear();
return 0;
}

double sub_result = 0.0;
double sub_last_result = last_result;
if(m_MathRoot.getVector().at(i+1).m_Type == SUB)
{
sub_last_result = m_MathRoot.getVector().at(i+1).sub.at(0).m_dValue;

for(size_t b = 1; b<m_MathRoot.getVector().at(i+1).sub.size(); b += 2)
{
if(b+1 >= m_MathRoot.getVector().at(i+1).sub.size())
{
printf("Syntax Error!\n");
m_MathRoot.clear();
return 0;
}
sub_result = Calculate_Factor(sub_last_result, m_MathRoot.getVector().at(i+1).sub.at(b+1).m_dValue, m_MathRoot.getVector().at(i+1).sub.at(b).m_Op);
sub_last_result = sub_result;
}
}

double right = 0;

if(m_MathRoot.getVector().at(i+1).m_Type == SUB)
{
right = sub_last_result;
}else{
right = m_MathRoot.getVector().at(i+1).m_dValue;
}

result = Calculate_Factor(last_result, right, m_MathRoot.getVector().at(i).m_Op);
last_result = result;
}

//We are done so clean up!
m_MathRoot.clear();

return result;

}

double Calculator::Calculate_Factor(double left, float right, char op)
{

if(op == '+')
{
left += right;
}
else if(op == '-')
{
left -= right;
}
else if(op == '*')
{
left *= right;
}
else if(op == '/')
{
left /= right;
}


return left;
}




Example Code:


if(m_Calculator.CanBeUsedInCalculator(str))
{
double val = m_Calculator.CalculateValue(str);

double intpart;
if(modf (val , &intpart) == 0.0)
{
printf("%i", (int)val);
}else{
printf("%f", val);
}
}
Check out my open source code projects/libraries! My Homepage You may learn something.

I'll have to put your code to the test alvaro and see who's runs better. ;) Mine is more code, but I think it makes it a little more robust.


I have to take offense to that... Your code crashes when there is a syntax error but you think it's more robust than mine? What part of my code is not robust?
Sorry I don't mean to offense, I was just saying that in sarcasm tongue.png. I've fixed up my code not to crash. Btw I've found a bug in your code alvaro. I've attached a comparison when using this argument. "5 - -4 * 3.141". Yours is a bit off. I was going to do a speed test for fun, but I didn't get around to it. I'm guesting yours maybe faster. Since mine goes through a lot of loops and syntax handling.
Check out my open source code projects/libraries! My Homepage You may learn something.
5 - -4 * 3.141 = 17.564

How much do you get?


Gotcha:
(5) - ( (-1) * (4) * (3.141) ) = (5) - ( (-1) * (12.564) ) = (5) - ( -12.564 ) = 5 + 12.564 = 17.564


Also:
<html>
<body>
<script>
document.write(eval('5 - -4 * 3.141 '));
</script>
</body>
</html>
I don't understand what you think the bug is...

This topic is closed to new replies.

Advertisement