12

I have been given the task of using java to produce a Sin table, however I seem to get some very weird results for some values of the input. I am using the below

System.out.println("| sin(" + currentPoint + ") = " + Math.sin(Math.toRadians(currentPoint)));

Where (int) currentPoint is a value in degrees (eg 90)

These are results I find weird

| sin(360) = -2.4492935982947064E-16
| sin(180) = 1.2246467991473532E-16
| sin(150) = 0.49999999999999994
| sin(120) = 0.8660254037844387

Expecting

sin(360) = 0
sin(180) = 0
sin(150) = 0.5
sin(120) = 0.866025404

Am I missing something?

phuclv
  • 37,963
  • 15
  • 156
  • 475
Pez Cuckow
  • 14,048
  • 16
  • 80
  • 130
  • 1
    According to [google](http://www.google.com/search?sourceid=chrome&ie=UTF-8&q=sin+360+degrees), `sin(360 degrees)` is in fact `0`. Are you sure you mean sine? – matt b Oct 18 '10 at 17:57
  • 1
    your expected results are interpreting the values as radians, whereas in your program you are considering them as degree measurements. – robert_x44 Oct 18 '10 at 18:04
  • 1
    Your code is correct, the expectations are wrong. – Ishtar Oct 18 '10 at 18:08
  • Sin 180 degrees = Sin (PI) = `Sin(PI) = 1.2246467991473532E-16` (according to java). Code `System.out.println("Sin(PI) = " + Math.sin(Math.PI));` – Buhake Sindi Oct 18 '10 at 18:52

8 Answers8

7

You're dealing with floating point numbers, looking for exact answers isn't going to work for all values. Take a look at What Every Computer Scientist Should Know About Floating-Point Arithmetic. You want your tests to be equivalent to your expectations within some delta. Note that the answers you're getting are pretty close. It's expressing values in bits that's biting you.

From the link:

Squeezing infinitely many real numbers into a finite number of bits requires an approximate representation. Although there are infinitely many integers, in most programs the result of integer computations can be stored in 32 bits. In contrast, given any fixed number of bits, most calculations with real numbers will produce quantities that cannot be exactly represented using that many bits. Therefore the result of a floating-point calculation must often be rounded in order to fit back into its finite representation. This rounding error is the characteristic feature of floating-point computation.

Paul Rubel
  • 26,632
  • 7
  • 60
  • 80
2

As mentioned above it is not an error, just the aproximation of computer's floating point arithmetic.

To get the expected answer, as sin() & cos() are between -1, 0 , +1, try to add 1 round it to the accurancy needed and substract 1.

x = round15(Math.sin(toRad(angle))+1)-1;

where round15 is defined

public double round15(double x){
    DecimalFormat twoDForm = new DecimalFormat("0.##############E0");
    String str = twoDForm.format(x);
    return Double.valueOf(str);
}

It works for me, hope future readers like it.

pvalle
  • 1,335
  • 1
  • 13
  • 20
2

If your code was System.out.println("| sin(" + currentPoint + ") = " + Math.sin(currentPoint)); you would expect this:

sin(360) = 0.958915723 
sin(180) = -0.801152636 
sin(150) = -0.71487643 
sin(120) = 0.580611184 

In other words, the sine of 360 radians is 0.9589, but the sine of 360 degrees is 0.

EDIT:
The reason you're seeing unexpected results is just due to lack of precision in the calculations. If you just format the results so they have fewer decimal places, the rounding will take care of it. Do something like this:

System.out.printf("| sin(%d) = %.7f\n", currentPoint, Math.sin(Math.toRadians(currentPoint)));

Then you will get results closer to what you expect.

Gabe
  • 84,912
  • 12
  • 139
  • 238
2

Your results are correct ... for approximation try this...

    result=Math.sin(Math.toRadians(value));
    result=format(result);


    private double format(double value) {
            return (double)Math.round(value * 1000000) / 1000000; //you can change this to round up the value(for two position use 100...)
        }
vnshetty
  • 20,051
  • 23
  • 64
  • 102
1

The posters above are right. The correct values you are expecting are:

Sin(360 degrees) = 0 Sin(180 degrees) = 0 Sin(150 degrees) = .5 Sin(120 degrees) = .866

The code is returning the correct answers. They just need to be rounded. Try this:

System.out.printf("%s%.3f","| sin(" + currentPoint + ") = ", (Math.sin(Math.toRadians(currentPoint))));

You can change the .3f value to different numbers if you want to improve or reduce decimal precision.

For some reason it displays the sin of 360 to be -0.00. I am sure there is a more elegant solution, but this should work.

EDIT: Beaten by seconds. Use the code above mine, it is easier to read.

1

Also note that Math.PI, which is a double value, is not PI, but just an approximation of PI, and Math.sin(Math.PI) gives you the double value which is the closest to actual mathematical value of sin(Math.PI).

Jeff
  • 11
  • 1
0

You must convert the angle into radians like this

Math.sin(Math.toRadians(90)) and the result must be 1

0

Below is the API description of the Math.sin method. Note the part in asterix. I would bet that the difference between your expected results and the once you get are defects of floatpoint calculation or rounding problems.

sin

public static double sin(double a)

Returns the trigonometric sine of an angle. Special cases:

    * If the argument is NaN or an infinity, then the result is NaN.
    * If the argument is zero, then the result is a zero with the

same sign as the argument.

A result must be within 1 **ulp** of the correctly rounded result. Results

must be semi-monotonic.

Parameters:
    a - an angle, in radians. 
Returns:
    the sine of the argument.
posdef
  • 6,498
  • 11
  • 46
  • 94