Home > Java > Improving the String math calculator

Improving the String math calculator

In Reducing the Necronomicon to numbers I demonstrated how we might parse and evaluate a String reduced to and resulting in a simple mathematical expression which can be evaluated. I’ve given the matter a little more thought in the interim and extended and refactored the calculator a little so that it works on doubles, which I went for in preference to float on grounds of overall utility. As I indicated in the earlier article, for simple calculation all that really was required was to handle the decimal places, and, of course, and what I omitted to mention at the time, to overload the calc method so that it handled doubles and returned doubles.  So this is what the code looks like.


public double sbExtendedMathEvaluator(StringBuffer sb)
    {
    double result = 0.0;
    char operator = ' ';
    String tmp = "";

    char[] aEval = sb.toString().toCharArray();
    int last = aEval.length;

    for (int i = 0; i < last; i++)
    {

    if(!isNumOrDecPlace(aEval[i])  )
    {
    if (isOperator(aEval[i]))   { operator = aEval[i]; }
    tmp = ""; // reset tmp
    continue;
    }

    tmp += Character.toString(aEval[i]);
    if(i + 1 == last){result = calc(result,operator,toDouble(tmp)); break;}

    if(!isNumOrDecPlace(aEval[i + 1])  ){  result = calc(result,operator,toDouble(tmp));   }
    }
return result;
}

The new syntax helpers for this are

public boolean isNumOrDecPlace(char c)
    {
    if((isInt(c)) || (isDecimalPlace(c )))    {return true;}
    return false;    }

public double toDouble(String tmp)
    {
    return Double.parseDouble(tmp);
    }

and isNumOrDecPlace’s dependency

public boolean isDecimalPlace(char c)
    {
    if (c == '.'){return true;}
    return false;
    }

And the overloaded calc method now looks like:

public double calc(double result, char operator, double val)
    {
    if (operator == '+')
    {return result + val;}
    if (operator == '+')
    {return result - val;}
    if (operator == '*')
    {return result * val;}
    if (operator == '/')
    {return result / val;}
     if (operator == '%') // modulus
    {return result % val;}
    // no op possible? just throw back the result unmutated
    // but we do need to handle the exceptions.... we'll get to those later
    return result;
    }

This all works pretty much as intended, so I’d like to consider now some further possibilities and make this a fully functional String math evaluator, which I’ll be addressing in some future articles.

First, I need to test this into the ground so I’ll be running the class through JUnit and doing some mock testing with something like (and probably will be) EasyMock. It’s generally good practice to write your JUnits upfront btw, however as a lot of this was written by the 20 cups of coffee and “let’s code it and see if it works” discovery method it wasn’t really feasible in this case so I substituted a number of ad hoc tests to keep an eye on how the code was coming along. Since I work almost exclusively in NetBeans, retrofitting the JUnits is merely a question of hitting Tools->Create Unit tests and then writing the test evaluations anyway.

The we have some other issues to explore to make the evaluation relatively complete. We need to be able to handle bracketed expressions like ” 1 + ( 2 * 3 )”. At the moment if you try and evaluate this as is, it will return 6 which is not quite the result we want. It will also need to handle signed values appropriately – at the moment it doesn’t handle signed values terribly well (it ignores them) e.g. “+10 + -10 ” will give you 10.0 as a result, again not what is wanted. It would also be nice if it could handle some simple expressions like “pow” and “sqrt”. We also need to be able to handle the exceptions which emerge e.g. divide by zero errors, or erroneously unbalanced bracketed expressions such as ” 1 + (2 *5) + 4)”.

Later I’ve had a look at and a think about at the mechanisms for doing the bracketed expression analysis and it looks potentially nasty but my current implementation is not a million light years away from what’s required to resolve this. I just need one of those much-vaunted sudden moments of absolute clarity to mop this one up! Wikipedia has the full lowdown on what’s needed here, and this is potentially non-trivial.

Advertisements
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: