5

Given a polynomial with a single variable x, and the value of x as input, compute its value. Examples:

eval("-2x^3+10x-4x^2","3")=-60

eval("x^3+x^2+x","6")=258

Description of issue: In this code I break the string into a substring whenever a +/- is encountered and pass the substring to a function which evaluates single term like "-2x^3". So my code for input = "-2x^3+10x-4x^2" calculates till "-2x^3+10x" only and skips "-4x^2" part.

Can anyone please tell me whats wrong here?

public class EvalPolyX2 {

    static String testcase1 = "-2x^3+10x-4x^2";
    static String testcase2 = "3";

    public static void main(String args[]){
        EvalPolyX2 testInstance = new EvalPolyX2();
        int result = testInstance.eval(testcase1,testcase2);
        System.out.println("Result : "+result);
    }

    public int eval(String str,String valx){

        int sum = 0;        
        String subStr = "";
        if(str.charAt(0) == '-')
        {
            int len = str.length();
            for (int i = 0; i < len; i++)
            {
                if(str.charAt(i) == '-' || str.charAt(i) == '+')
                {                   
                    subStr = str.substring(0, i);
                    System.out.println("subStr="+subStr);
                    sum += evalSubPoly(subStr, valx);
                    str = str.substring(i);
                    len = str.length();
                    i = 0;
                }               
            }
        }
        else if(str.charAt(0) != '-')
        {
            str = '+' + str;
            int len = str.length();
            for (int i = 0; i < len; i++)
            {
                if(str.charAt(i) == '-' || str.charAt(i) == '+')
                {
                    subStr = str.substring(0, i);
                    System.out.println("subStr="+subStr);
                    sum += evalSubPoly(subStr, valx);
                    str = str.substring(i);
                    len = str.length();
                    i=0;
                }
            }
        }
        return sum;
    }

    public int evalSubPoly(String poly,String valx){
        int len = poly.length();
        String num = "";
        String power = "";
        int exp = 0, coeff = 0;

        for(int i = 0; i < len; i++)
        {
            if(poly.charAt(i) == 'x')
            {
                num = poly.substring(0, i);
                coeff = Integer.parseInt(num);                              
            }
            if(poly.charAt(i) == '^')
            {
                power = poly.substring(i+1, len);
                exp = Integer.parseInt(power);
            }                       
        }

        if(power.equals(""))
            exp = 1;
        System.out.println("coeff="+coeff);

        int sum = 1;
        int x = Integer.parseInt(valx);

        for (int i = 0; i < exp; i++)
        {
            sum = sum*x;
        }
        System.out.println("sum="+sum);
        sum = sum*coeff;

        return sum;
    }
}
abhishek14d
  • 89
  • 2
  • 12
  • Let me rephrase - When trying to run your code sample as is, I get `Exception in thread "main" java.lang.NumberFormatException: For input string: "+10"`. This means your code sample doesn't reproduce the problem, which makes life more difficult for us. – Bernhard Barker Aug 22 '13 at 17:05
  • Dukeling is right, because you are including the +/- sign in the string after you've found it. To avoid this, you need to change `str = str.substring(i);` to be `str = str.substring(i+1);` that way the rest of the string starts after the +/- rather than including it. – Paris Nelson Aug 22 '13 at 17:10
  • But doesn't he need to include it if it's '-'? Otherwise the fact that it's '-' rather than '+' gets completely lost. – ajb Aug 22 '13 at 17:56

6 Answers6

2

What's wrong with using regex? You can split the polynomial into monomials, evaluate each, and add all of the results.

private static final Pattern monomial = Pattern
        .compile("([+-])?(\\d+)?x(?:\\^(\\d+))?");

public static int eval(String str, String valx) {
    Matcher m = monomial.matcher(str);
    int x = Integer.parseInt(valx);

    int total = 0;
    while (m.find()) {
        String mul = m.group(2);
        int value = (mul == null) ? 1 : Integer.parseInt(m.group(2));

        String pow = m.group(3);
        value *= (pow == null) ? x : (int) Math.pow(x,
                Integer.parseInt(pow));

        if ("-".equals(m.group(1)))
            value = -value;

        total += value;
    }

    return total;
}

System.out.println(eval("-2x^3+10x-4x^2", "3"));
System.out.println(eval("x^3+x^2+x", "6"));
-60
258
arshajii
  • 127,459
  • 24
  • 238
  • 287
  • Definitely the clearest (and that's the exact same regex I would have used), but the title makes me think it's a class assignment and regexes are forbidden. – ajb Aug 22 '13 at 23:36
1

This code replacement should help

  if(str.charAt(i) == '-' || str.charAt(i) == '+' || i == (len - 1))
  {   
    if(i == len - 1)
    {
     i++;
    }
    ...

Though there could be better ways, but I only wanted to show a way out here. The reason is you are looking for + or - as the delimiter. But the last part of the expression will not end with either of these but just probably EOL

Shiva Kumar
  • 3,111
  • 1
  • 26
  • 34
1
  1. You need to account for the last term (the if-statement will only trigger when a - or + is found, which there isn't at the end).

    One easy way to do this is to replace:

    for (int i = 0; i < len; i++)
    {
        if (str.charAt(i) == '-' || str.charAt(i) == '+')
    

    with:

    //                 v one more iteration
    for (int i = 0; i <= len; i++)
    {
        if (i == len || str.charAt(i) == '-' || str.charAt(i) == '+')
    //      \------/
    //   extra condition
    

    The above simply goes on for one more iteration and, on that iteration, always goes into the if-statement, causing the last term to be processed.

  2. You can also simplify

    if (str.charAt(0) == '-')
    {
      // common code
    }
    else if (str.charAt(0) != '-')
    {
      str = '+' + str;
      // common code
    }
    

    To:

    if (str.charAt(0) != '-')
    {
      str = '+' + str;
    }
    // common code
    
  3. There's also a bug with handling +. I get a NumberFormatException for this. One way to handle it is to ignore the + between the terms (and not adding a + to the start):

    if (i != len && str.charAt(i) == '+')
      str = str.substring(i+1);
    else
      str = str.substring(i);
    
  4. And you might as well make your functions static and call them directly rather than declaring a new instance of your class.

Test.

Bernhard Barker
  • 54,589
  • 14
  • 104
  • 138
0

The simple answer is that when you do this:

           if(str.charAt(i) == '-' || str.charAt(i) == '+')
            {
                subStr = str.substring(0, i);

the effect is that you're setting subStr to text just before the - or +, and evaluating it. But since there's no - or + at the end of the string, there's no way this logic will evaluate the last term of the polynomial, since it only evaluates substrings that are right before a - or +.

P.S. That's just one problem I noticed. I don't know if the rest of the logic is correct.

ajb
  • 31,309
  • 3
  • 58
  • 84
0

When you parse the string, you look for +/- and only stop if you find them. This works for the first two terms, but when you get down to "-4x^2" the loop won't stop because there is no +/-. So in addition to the conditions you have, you need to add code so that when the end of the string is reached, what you have left is the last term. So what you want to have is this

if(str.charAt(0) == '-')
    {
        int len = str.length();
        for (int i = 0; i < len; i++)
        {
            if(str.charAt(i) == '-' || str.charAt(i) == '+')
            {                   
                subStr = str.substring(0, i);
                System.out.println("subStr="+subStr);
                sum += evalSubPoly(subStr, valx);
                str = str.substring(i+1);
                len = str.length();
                i = 0;
            }               
        }
        System.out.println("subStr="+str);
        sum += evalSubPoly(str, valx);
    }


    else if(str.charAt(0) != '-')
    {
        str = '+' + str;
        int len = str.length();
        for (int i = 0; i < len; i++)
        {
            if(str.charAt(i) == '-' || str.charAt(i) == '+')
            {
                subStr = str.substring(0, i);
                System.out.println("subStr="+subStr);
                sum += evalSubPoly(subStr, valx);
                str = str.substring(i+1);
                len = str.length();
                i=0;
            }
        }
        System.out.println("subStr="+str);
        sum += evalSubPoly(str, valx);
    }

I will also throw out the disclaimer that there may be more errors, but this is the major one causing your problem.

EDIT: added change to else if statement and added change mentioned in my comment above

Paris Nelson
  • 131
  • 6
0

With regular expressions, you can get a more simple solution. And, do you want support for simple constants? Try the next:

public class EvalPolyX2 {
    public static void main(String args[]) {
        System.out.println("Result: " + eval("x^3+x^2+x", 6));
    }
    public static int eval(String eq, int val) {
        int result = 0;
        String mons[] = eq.split("(?=[+-])(?!\\B)");
        for (String str : mons) {
            str = str.replace("+", "");
            if (str.contains("x")) {
                double a = 1, b = 1;
                String[] comps = str.split("x\\^?");
                if (comps.length > 0) {
                    a = comps[0].isEmpty() ? 1 : Integer.parseInt(comps[0]);
                }
                if (comps.length > 1) {
                    b = Integer.parseInt(comps[1]);
                }
                result += a * Math.pow(val, b);
            } else {
                result += Integer.parseInt(str);
            }
        }
        return result;
    }
}
Paul Vargas
  • 41,222
  • 15
  • 102
  • 148