-1

I have:

double num1 = sc.nextInt();

I used:

double sin  = Math.sin(Math.toRadians(num1));

and made the output:

if(calc.contains("sin")) {
    System.out.println (sin);
}

if i typed in for num1:

30 and it calculates sin. It gives me 0.49999999999999994

Marcs
  • 3,768
  • 5
  • 33
  • 42
shane
  • 21
  • 2
  • 1
    Please read [What Every Computer Scientist Should Know About Floating-Point Arithmetic](https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) – Ted Hopp Nov 24 '16 at 01:55
  • 1
    Sorry, I don't think this is a duplicate of that question. The usual "Is floating-point math broken" explains why certain numbers like `0.1` can't be represented exactly. But 0.5 **can** be represented exactly, so the answer to this question must be something different. – ajb Nov 24 '16 at 02:11
  • @ajb Yes, 0.5 can be represented exactly, but pi/6 cannot. So we convert an exact 30 into an inexact pi/6, then find a sine which is not quite 0.5. – Dawood ibn Kareem Nov 24 '16 at 02:20
  • My opinion is that Java ought to provide methods called `sindegrees`, `cosdegrees` and `tandegrees` to prevent this issue. – Dawood ibn Kareem Nov 24 '16 at 02:22
  • While there _is_ a perfect representation for 0.5, there certainly _is not_ for the transcendental number pi/6 radians, which is the argument to `sin`. The answer agrees with an error of -1 ulp (unit of least precision) in the 53-bit mantissa, which is about as good as floating point computation can do. – Gene Nov 24 '16 at 02:24
  • Very true, They should add those methods @DavidWallace – shane Nov 24 '16 at 02:26
  • Actually, an even better feature would be an `enum` called `AngleUnit` with values `DEGREES`, `RADIANS` and `GRADS`, and methods `Math.sin(double, AngleUnit)`, `Math.cos(double, AngleUnit)` and `Math.tan(double, AngleUnit)`. Maybe something similar for the inverse trig functions too. – Dawood ibn Kareem Nov 24 '16 at 03:50
  • @DavidWallace Out of curiosity, how would `sin` and `cos` functions that handle degrees work? It seems to me that all it could do is make special checks for sin(30) and cos(60) [and their equivalents in other quadrants], and maybe multiples of 90, but convert to radians otherwise. If the formulas used to compute `sin` and `cos` were adjusted to work with degree arguments, I'd be concerned that roundoff errors would be introduced. – ajb Nov 24 '16 at 18:35
  • @ajb I don't know what algorithm they might use. But I'm sure there are a huge number of examples of degree values that behave this way; i.e. give a result that's not within one ULP of the "correct" answer if they are converted to radians and then passed to the trig function. It wouldn't just be multiples of 30 degrees. I think the argument in your answer proves it. – Dawood ibn Kareem Nov 24 '16 at 19:21
  • @DavidWallace I see what you mean--it might lead to a smaller error if we don't introduce the error when converting to radians. The code I've seen uses a polynomial (might be the first 5 or 6 terms of the Taylor series, but I don't know), with some other calculations involved. Computing in terms of degrees should mean just using different coefficients. So yes, that might produce a more accurate result. I think this calls for an experiment. I'm still not convinced it would get sin(30) right without special checks, but maybe it would. – ajb Nov 24 '16 at 19:26

2 Answers2

2

π/6 cannot be represented exactly in a computer (it can't be represented exactly on paper, either). This will cause the result to be a little bit off too. Using "bc", a Unix high-precision calculator (note: I don't know just how accurate it is for sine and cosine), I find that the actual value in your program will be π/6 + ε where ε is about 5.3604 x 10-17. Using the formula for sin(x+y), the expected result should be sin π/6 cos ε + sin ε cos π/6. cos ε is about 1 - 10-33, so this difference won't be enough to affect the result. However, sin ε cos π/6 is about 4.64 x 10-17. So the actual result should be something like 0.4999999999999999535774978 instead of 0.5.

This result won't be represented exactly in a double, either. Because a double has a mantissa of 52 bits, numbers whose values are >= 0.25 and < 0.5 could be represented by numbers that are off by as much as 2-54. The double used to represent this result would be 0.499999999999999944488848768742172978818416595458984375. When this is printed with System.out.println, it will stop after a certain number of decimal places are printed, so this gets truncated to 0.49999999999999994, which is the result you're seeing. (The number of digits displayed is discussed in [http://docs.oracle.com/javase/8/docs/api/java/lang/Double.html#toString-double-](this javadoc).

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

sin(30°) is surely 0.5, but there is not a dictionary that contains a key of 30° with value 0.5, so computer need to calculate it.

enter image description here

The formula is showing above.

Let's calculate sin(30°), 30° = π/6, so f(x)= π/6 - π^3/1296 - π^5/933120 - ....

And then in this process, accuracy error can lead to "unpredictable"(actually predictable) problems.

Sraw
  • 18,892
  • 11
  • 54
  • 87
  • I think this answer misses the point. The contract for `sin` says that the result must be within 1 ULP of "correct". But the problem is with the argument to `sin` - it's the `π/6` where the imprecision creeps in. – Dawood ibn Kareem Nov 24 '16 at 02:36
  • @DavidWallace You are right, the imprecision of `π/6` is the actual accuracy error in this case. – Sraw Nov 24 '16 at 02:56