[Java] Sines, cosines and tangents. One is wrong...
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
[Java] Sines, cosines and tangents. One is wrong...
Friends,
I am trying to put some lines of codes to learn java and following is what I've ran into today...
I was trying to get the basics of trigonometric operations. I coded a small script to display me the sines from 0 to <360 in 30 degree increments. As we all know, sines from 0 to 180 [or 0 to pi) are positive. For sin(30) and sin(60) I got negative values. Similar things went on for cos. So, knowing that tan(x)=sin(x)/cos(x), I have written the following code for testing:
Code:
package javaapplication4;
public class Main {
public Main() {
}
public static void main(String[] args) {
int x; double t;
for (x=0; x<360; x += 30)
{
double sin_x = Math.sin(x);
double cos_x = Math.cos(x);
double tan_x = Math.tan(x);
System.out.println("Sin(" +x +")" +"=" +sin_x);
System.out.println("Cos(" +x +")" +"=" +cos_x);
t = sin_x / cos_x;
if (t == tan_x)
{
System.out.println("True");
}
else System.out.println("False");
}
}
}
1. Sine of any degree between 0 and 90 (0 to pi/2) can't be negative
2. Cosine of any degree 0 and 90 (0 to pi/2) can't be negative
3. Cos(90) (or cos(pi/2)) ==0
And finally, from the code sin(x)/cos(x) != tan(x)
Can anyone tell me what I am missing? I believe I am making a very small mistake that confuses me.
If it helps, I am running JDK 5 with Netbeans (latest version, I downloaded yesterday: 21MAY06 SUN) on SuSE 9.3 Pro.
In java, all the Math trig functions are static, take double value radians as arguments and return double values and return radian values ( not angles in degrees) for inverse trig. functions.
So in your problem,
double rad = angle * Math.PI/ 180.0;
double val = Math.cos(rad);
Also, it is not a great idea to compare 2 floating point numbers.. Even if there is a difference in 43 rd decimal, it will return false. You must google some article on floating point number comparison to know the pitfalls.
@graemef: It shouldn't have mattered, whether degrees or radians I suppose.
@graemef & ppanyam: I will try tonight with the radian conversion and post the results here.
@ppanyam: I just wanted to make sure that there's an error with the results of sines and cosines. My intention was not to compare the two results, but to prove myself that there's something wrong.
I just wanted to say good luck When I said that above I meant what the actual function SHOULD take as input not what is was taking for input. Sorry for confusion
I'm continuing this post so other people can benefit from this nice discussion.
@Centinul: No need to be sorry.
@graemef & ppanyam: As I said I rushed home and tried with your suggestions. Here is the modified version of my code:
Code:
package javaapplication4;
public class Main {
public Main() {
}
public static void main(String[] args) {
int x; double t;
for (x=0; x<=360; x += 30)
{
double rad = x * Math.PI/180;
double sin_x = Math.sin(rad);
double cos_x = Math.cos(rad);
double tan_x = Math.tan(rad);
t = sin_x / cos_x;
System.out.println("Sin(" +x +")" +"=" +sin_x);
System.out.println("Cos(" +x +")" +"=" +cos_x);
System.out.println("Tan(" +x +")" +"=" +tan_x);
System.out.println("Computed tan(" +x +")" + "=" +t);
if (t == tan_x)
{
System.out.println("True");
}
else System.out.println("False");
}
}
}
Beware that I'm using radians for computation and degrees for displaying the angles [if you have gone through degrees in all your math classes, radians do not seem friendly]. And I have also modified the x variable slightly. Now it's not less than 360 but less than or equal to.
1. The code can display zeroes fine, as we see in 0 degrees [or 0 radians]. However, this is not sometimes the case. Check out Cos(270) [or Cos(3*PI/2)]. It should be definitely zero. But it is displayed as something very very close to zero. And the sign is negative. Is it implicitly taking the lim (x->2*PI/3-) cos(x)? Seems so
2. Tan(90) [or Tan(PI/4)] is +infinity. In our output, it is 1.633123935319537E16, which is a close resemblance of +infinity. Is this the case the outputs are handled? Just out of curiosity.
I am asking all these questions and bothering you all, because I wonder why the outputs are displayed with slight + or - values? Just because they are double? I don't think so. If that was the case, Cos(0) wouldn't be displayed as 1.0 I think. Just see Sin(30)=Cos(60), which is 0.5 but once it is 0.49999999999999994 and then 0.5000000000000001.
@ppanyam: The output is the proof of your last post, which you said "Also, it is not a great idea to compare 2 floating point numbers.. Even if there is a difference in 43 rd decimal, it will return false.". Just check out the Tan(300)=-1.732050807568877 and Computed tan(300)=-1.7320508075688767 and your point is obvious.
For display purposes you probably want to round the value first. Since math.round() returns an integer (unless there is a floating point function that performs rounding) you may want to scale round and then scale back. For example if you want hold 1.6331239 to three decimal places, scale by multiplying by 10 to the power 3 giving 1633.1239, then round giving 1633 and the divide by 10 to the power 3 giving 1.633. When it comes to numbers like 0.4999999 you will get .5 and 6.123E-17 will become zero.
I'm a huge fan of Java. But there are important issues involving numeric programming that (sadly) far too few programmers are aware of. These issues have to do with floating point in *ANY* programming language. Some languages are better (Fortran, anybody?) and some are worse (Visual Basic, for example); Java kind falls in the middle.
Distribution: Debian /Jessie/Stretch/Sid, Linux Mint DE
Posts: 5,195
Rep:
Uhm... is this language dependent or dependent on how well a library is implemented?
If I am not mistaken, a sine or cosine and all other mathematic functions on a computer are calculated, by doing a series of addtions of fractions (Taylor series?). Not sure, I only know the expression in Dutch. Anyway, this involved a whole lot of additions and divisions in floating point arithmetic. Any outcome is just an approximation of the final value. The approximation is better and the error smaller if the series is longer. Even in algebra, the outcome is not quite exact. In computers the error due floating point accuracy errors is added to the inaccuracy of the outcome.
Taking this into account, and error of 1E-15 is not bad at all. It cannot be exact by nature.
One could make a case that the "java.Math" *is* part/parcel of the Java language.
You're absolutely correct: "1E-15" *isn't* bad, and "It cannot be exact by nature". All true.
But nevertheless, there are serious problems with both the Java language (how floating point values are represented, for example) and with the standard libraries. Here's another article that might be of interest:
Distribution: Debian /Jessie/Stretch/Sid, Linux Mint DE
Posts: 5,195
Rep:
You know, I am the generation that used to include a punch card with JCL statements in the card deck to link in the NAG library to my FORTRAN program, and then run it on an IBM 370 mainframe...
You could link another library in as well, if you thought it gave better performance or accuracy.
I see what you mean now and how JAVA is different.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.