-1

I was wondering how to replace common trigonometric values in an expression. To put this into more context, I am making a calculator that needs to be able to evaluate user inputs such as "sin(Math.PI)", or "sin(6 * math.PI/2)". The problem is that floating point values aren't accurate and when I input sin(Math.PI), the calculator ends up with:

1.2245457991473532E-16

But I want it to return 0. I know I could try replacing in the expression all sin(Math.PI) and other common expressions with 0, 1, etc., except I have to check all multiples of Math.PI/2. Can any of you give me some guidance on how to return the user the proper values?

Henry Zhu
  • 2,488
  • 9
  • 43
  • 87

2 Answers2

1

You're running into the problem that it's not quite possible to express a number like pi in a fixed number of bits, so with the available machine precision the computation gives you a small but non-zero number. Math.PI in any case is only an approximation of PI, which is an irrational number. To clean up your answer for display purposes, one possibility is to use rounding. You could instead try adding +1 and -1 to it which may well round the answer to zero.

This question here may help you further: Java Strange Behavior with Sin and ToRadians

Community
  • 1
  • 1
Peadar
  • 79
  • 1
  • 3
  • 1
    That is very general. I was wondering how to replace Math.PI, 2*Math.PI, etc. with their proper integer values. I know that it has to be rounded but how do I do so? – Henry Zhu Aug 05 '15 at 21:08
  • Is your calculator implementing its own parse engine for the user inputs? If so, you could check for isolated integer cases of PI but you are going to run into problems if a user enters a string that's mathematically equivalent. In essence, you'd be moving from building a simple calculator to building a full symbolic math engine, which is an entirely different level of difficulty. – Peadar Aug 05 '15 at 21:16
  • I am using a math library called MathEval. – Henry Zhu Aug 05 '15 at 21:16
  • I ran into this issue with a calculator app I wrote. People complained that sin(pi) wasn't returning zero. One of these days I'm going to modify the app so that when the sin() function sees an input that's as close to pi as the language can represent, it just returns zero. Likewise for pi/2 and 3*pi/2 – Edward Falk Aug 05 '15 at 21:34
1

Your problem is that 1.2245457991473532E-16 is in fact zero for many purposes. What about simply rounding the result yielded by sin? With enough rounding, you may achieve what you want and even get 0.5, -0.5 and other important sin values relatively easily.

If you really want to replace those functions as your title suggests, then you can't do that in Java. Your best bet would be to create an SPI specification for common functions that could either fall back to the standard Java implementation or use your own implementation, which replaces the Java one.

Then users of your solution would need to retrieve one of the implementations using dependency injection of explicit references to a factory method.

Akira
  • 4,001
  • 1
  • 16
  • 24
  • Thanks. I'll guest I just have to stick to rounding then. – Henry Zhu Aug 05 '15 at 21:37
  • If your intention is purely didactic (to easily show which number you are supposed to get), then you can probably safely round numbers. Alternatively, if you really want precision (which I bet is not that necessary), you can keep the returned value in an internal variable and keep showing the round result, which is easier to understand. But nevertheless, important results such as sqrt(2)/2 will still appear hard for a human to identify. – Akira Aug 05 '15 at 21:41