-1

The code is giving values like 0.49999 instead of 0.5 which is the correct answer when doing sin(30), and 1.0 instead of 1. I have tried messing with it a bit but I have not found a working code. Does anybody know why this is happening and have a fix? Any help would be greatly appreciated since I am quite new to coding.

public static double eval(final String str) {
    return new Object() {
        int pos = -1, ch;

        void nextChar() {
            ch = (++pos < str.length()) ? str.charAt(pos) : -1;
        }

        boolean eat(int charToEat) {
            while (ch == ' ') nextChar();
            if (ch == charToEat) {
                nextChar();
                return true;
            }
            return false;
        }

        double parse() {
            nextChar();
            double x = parseExpression();
            if (pos < str.length()) throw new RuntimeException("Unexpected: " + (char)ch);
            return x;
        }
        

        double parseExpression() {
            double x = parseTerm();
            for (;;) {
                if      (eat('+')) x += parseTerm(); // addition
                else if (eat('-')) x -= parseTerm(); // subtraction
                else return x;
            }
        }

        double parseTerm() {
            double x = parseFactor();
            for (;;) {
                if (eat('*')) x *= parseFactor(); // multiplication
                else if (eat('/')) x /= parseFactor(); // division
                else return x;
            }
        }

        double parseFactor() {
            if (eat('+')) return parseFactor(); // unary plus
            if (eat('-')) return -parseFactor(); // unary minus

            double x;
            int startPos = this.pos;
            if (eat('(')) { // parentheses
                x = parseExpression();
                eat(')');
            } else if ((ch >= '0' && ch <= '9') || ch == '.') { // numbers
                while ((ch >= '0' && ch <= '9') || ch == '.') nextChar();
                x = Double.parseDouble(str.substring(startPos, this.pos));
            } else if (ch >= 'a' && ch <= 'z') { // functions
                while (ch >= 'a' && ch <= 'z') nextChar();
                String func = str.substring(startPos, this.pos);
                x = parseFactor();
                if (func.equals("sqrt")) x = Math.sqrt(x);
                else if (func.equals("sin")) x = Math.sin(Math.toRadians(x));
                else if (func.equals("cos")) x = Math.cos(Math.toRadians(x));
                else if (func.equals("tan")) x = Math.tan(Math.toRadians(x));
                else throw new RuntimeException("Unknown function: " + func);
            } else {
                throw new RuntimeException("Unexpected: " + (char)ch);
            }

            return x;

        }
    }.parse();
}
qfn
  • 1
  • 1
  • 4
    Does this answer your question? [Why are floating point numbers inaccurate?](https://stackoverflow.com/questions/21895756/why-are-floating-point-numbers-inaccurate) – Markus Kauppinen Jan 20 '21 at 15:47
  • 1
    Related: [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – Markus Kauppinen Jan 20 '21 at 15:50
  • @qfn- `else if (func.equals("sin")) x = (float) Math.sin(Math.toRadians(x))` is an option for you? – amitd Jan 20 '21 at 16:07

1 Answers1

0

That's only to be expected, due to the issues with precision for floating point numbers. For more info, see Why are floating point numbers inaccurate? or Is floating point math broken?.

If you run this program

public class Main {
    public static void main(String[] args) {
        System.out.println(Math.sin(Math.toRadians(30)));
        System.out.println(Math.tan(Math.toRadians(45)));
    }
}

you will get output like

0.49999999999999994                                                                       
0.9999999999999999

(Live example)

Also note that Math.toRadians(), Math.sin(), and Math.tan() all have a double return type, meaning they will never return an integer type. If you knew something should return an integer value, you can cast to an integer type.

Shane Bishop
  • 3,905
  • 4
  • 17
  • 47