From school mathematics we know that the tangent has the definition
tan(α) = sin(α) / cos(α)
and we differentiate between four quadrants based on the angle that we supply to the functions. The sign of the sin, cos and tan have the following relationship (where we neglect the exact multiples of π/2):
Quadrant Angle sin cos tan
-------------------------------------------------
I 0 < α < π/2 + + +
II π/2 < α < π + - -
III π < α < 3π/2 - - +
IV 3π/2 < α < 2π - + -
Given that the value of tan(α) is positive, we cannot distinguish, whether the angle was from the first or third quadrant and if it is negative, it could come from the second or fourth quadrant. So by convention, atan() returns an angle from the first or fourth quadrant (i.e. -π/2 <= atan() <= π/2), regardless of the original input to the tangent.
In order to get back the full information, we must not use the result of the division sin(α) / cos(α) but we have to look at the values of the sine and cosine separately. And this is what atan2() does. It takes both, the sin(α) and cos(α) and resolves all four quadrants by adding π to the result of atan() whenever the cosine is negative.
Remark: The atan2(y, x) function actually takes a y and a x argument, which is the projection of a vector with length v and angle α on the y- and x-axis, i.e.
y = v * sin(α)
x = v * cos(α)
which gives the relation
y/x = tan(α)
Conclusion:
atan(y/x) holds back some information and one can only assume that the input came from quadrants I or IV. In contrast, atan2(y,x) gets all the data and thus can resolve the correct angle.
From school mathematics we know that the tangent has the definition
tan(α) = sin(α) / cos(α)
and we differentiate between four quadrants based on the angle that we supply to the functions. The sign of the sin, cos and tan have the following relationship (where we neglect the exact multiples of π/2):
Quadrant Angle sin cos tan
-------------------------------------------------
I 0 < α < π/2 + + +
II π/2 < α < π + - -
III π < α < 3π/2 - - +
IV 3π/2 < α < 2π - + -
Given that the value of tan(α) is positive, we cannot distinguish, whether the angle was from the first or third quadrant and if it is negative, it could come from the second or fourth quadrant. So by convention, atan() returns an angle from the first or fourth quadrant (i.e. -π/2 <= atan() <= π/2), regardless of the original input to the tangent.
In order to get back the full information, we must not use the result of the division sin(α) / cos(α) but we have to look at the values of the sine and cosine separately. And this is what atan2() does. It takes both, the sin(α) and cos(α) and resolves all four quadrants by adding π to the result of atan() whenever the cosine is negative.
Remark: The atan2(y, x) function actually takes a y and a x argument, which is the projection of a vector with length v and angle α on the y- and x-axis, i.e.
y = v * sin(α)
x = v * cos(α)
which gives the relation
y/x = tan(α)
Conclusion:
atan(y/x) holds back some information and one can only assume that the input came from quadrants I or IV. In contrast, atan2(y,x) gets all the data and thus can resolve the correct angle.
std::atan2 allows calculating the arctangent of all four quadrants. std::atan only allows calculating from quadrants 1 and 4.
math - Java: Tangent method - Stack Overflow
limits - Confusion about atan vs atan2 - Mathematics Stack Exchange
java - Guarantees concerning Math.atan2 - Stack Overflow
Fast Atan2 [Again] - Shared Code - JVM Gaming
Videos
I've been calculating rotation needed between two 3d points, and I'm having some slight trouble.
You can use very basic sohcahtoa to find the angle needed between the two points by making a right triangle and just doing arctan of opposite/adjacent (the two sides). Now this only works if all of the values are positive, as, for example, arctan(-5/-4) == arctan(5/4). I do remember learning something about fixing this back when I learned about trig identities in school, and how to fix it, but my friend sent me some code, and he used Math.atan2 instead of tangent.
Now his code works perfectly, and was not too different from mine, and it really made me wonder what Math.atan2 does. I searched up on the internet, and didn't understand a word of the descriptions. Can someone show me what Math.atan2 is in normal math writing?
Yes, you do indeed want atan, or sometimes, atan2. The difference between the two is that atan will fail under some circumstances when one of the side lengths are zero. While that may be unlikely for triangles, it is a possibility for some other, more general uses of atan. In addition, the atan function gives you an angle limited to the interval [-pi/2,pi/2]. So if you think about the atan function as a function of two inputs, (x,y), atan(y/x) will yield the same result as atan((-y)/(-x)). This is a serious flaw in some circumstances.
To solve these problems, the atan2 is defined such that it yields the correct result for all values of x and y, in any quadrant. One would use it as
atan2(oppositesidelength,adjacentsidelength)
to yield a consistent result.
Of course, for use in a non-degenerate triangle, the simple call to atan(opposite/adjacent) should be entirely adequate for your purposes.
Yep, you want atan, the arc tangent. This is the inverse of tangent; same thing with sin and arc sine, cosine and arc cosine, etc. These are alternative mathematical terminology for these functions' inverses.
Notice how atan returns angles from -π/2 to π/2, by the way. That's a hint that it's an inverse function (tangent takes angles and spits out ratios, arc tangent takes ratios and spits out angles). It is also important to recognize the restricted range. You won't necessarily get back your original angle, since tangents repeat every π radians (every 180°) — tan(π) = 0, but atan(0) = 0, not π.
φ = atan(m) converts the slope m of a line into the bearing angle. If the slope is zero, the angle is zero (by convention). If the slope is -∞ then the angle is -π/2 and if the slope is +∞ the angle is +π/2.
The result is limited to the 1st and 4th quadrants.
φ = atan(dy,dx) converts the direction defined by (dx,dy) into the bearing angle. If the direction points to the 2nd or 3rd quadrants (based on the signs of the arguments) then the angle result will vary between -π and +π.
Some environments define φ = atan(dx,dy) so care must be taken to get the correct order of arguments.
You must choose which function you need, as you pointed out when m=dy/dx the results are not always the same. There are cases when atan2() is preferred and cases where it is not. There are other cases you need positive angles only between 0 and π and there you use φ = acos(dx/sqrt(dx**2+dy**2)).
There is no universally proper way to do the conversion, as it depends on your assumptions related to the angle result.
Here is a graph of atan(m)

and the graph of acos(1/sqrt(1+m^2))

Both produce identical values for positive slope m, but the second one returns only the positive branch of angles for negative slope m.
and here is atan2(dx=1, dy=m)

which is identical to atan() as the direction information is lost since dx is always positive.
This is probably beating a dead horse, since the other answer explained the basic usages of $\arctan,$ $\arccos,$ and $\operatorname{atan2},$ but I don't think the other answer explained explicitly why your particular graph ended up exactly the way it did. I will focus on just that.
What you appear to be trying to do is (in effect) to plot the direction from the origin of a Cartesian plane to the point $\left(-w^2 + \frac1{C\cdot L},-\omega\cdot\frac RL\right),$ measured as an angle counterclockwise from the positive $x$-axis, for positive values of $\omega.$
Based on the results you are getting, I suppose that $C,$ $L,$ and $R$ are all positive or all negative. So when $\omega = 0,$ this point is simply $\left(\frac1{C\cdot L},0\right),$ which is a point on the positive $x$-axis and therefore has angle $0.$
As $\omega$ increases, $-w^2 + \frac1{C\cdot L}$ and $-\omega\cdot\frac RL$ both decrease. Initially the point $\left(-w^2 + \frac1{C\cdot L},-\omega\cdot\frac RL\right)$ moves downward from the $x$-axis into the fourth quadrant, but because of the $-\omega^2$ term this point starts moving left with increasing speed relative to its downward motion.
Eventually the point $\left(-w^2 + \frac1{C\cdot L},-\omega\cdot\frac RL\right)$ crosses from the fourth quadrant into the third quadrant. That is the point at which the arc tangent function "jumps" in your graph, because when $\frac yx$ is positive, $\arctan\frac yx$ always gives a first-quadrant answer, an angle between $0$ and $\frac\pi2,$ never an angle between $-\pi$ and $-\frac\pi2.$ Angles that you wanted to be reported as slightly less than $-\frac\pi2$ are reported as slightly less than $\frac\pi2$ instead.
Using $\operatorname{atan2}$ is a simple fix because when $(x,y)$ is in the third quadrant, $\operatorname{atan2}(y,x)$ gives an angle between $-\pi$ and $-\frac\pi2,$ just as you desire.
But if you want to use the older $\arctan$ function, another simple fix is to rotate the point $\left(-w^2 + \frac1{C\cdot L},-\omega\cdot\frac RL\right)$ by $\frac\pi2$ radians counterclockwise so that it goes from the first quadrant to the fourth, during which there is no "jump" in the output of $\arctan\frac yx,$ and then subtract $\frac\pi2$ to bring the angle values back to the expected interval between $-\pi$ and $0.$ You can do this by defining
$$ f(\omega) = \arctan\left(\frac{-w^2 + \frac1{C\cdot L}}{\omega\cdot \frac RL}\right) - \frac\pi2. $$
This will plot the same as your second figure. It is possible to use the old $\arctan$ function here because the angle outputs you want all lie in a single interval of width $\pi,$ just like the output of $\arctan$; you just need something like the rotation/shift described above to deal with the different positions of these equally-wide intervals on the real number line.
Does anyone know if it is guaranteed to return the same value for equivalent pairs of int parameters?
Simply put, no. The Math documentation is the source of truth, and it provides no guarantee beyond the 2 ulp limit you reference. This is by design (as we'll see below), therefore any other source is either exposing an implementation detail or simply wrong.
Attempting to find lower bounds heuristically is impractical, since the behavior of Math is documented to be platform-specific:
Unlike some of the numeric methods of class
StrictMath, all implementations of the equivalent functions of classMathare not defined to return the bit-for-bit same results. This relaxation permits better-performing implementations where strict reproducibility is not required.
Therefore even if you see tighter bounds in your tests there is no reason to believe these bounds are portable across platforms, processors, or Java versions.
However, as Math's documentation notes, StrictMath has more explicit behavior. StrictMath is documented to perform consistently across platforms, and is expected to have the same behavior as the reference implementation fdlibm. That project's readme notes:
FDLIBM is intended to provide a reasonably portable ... reference quality (below one ulp for major functions like sin,cos,exp,log) math library.
You can reference the source code for atan2 and determine precise bounds by examining its implementation; any other implementations of StrictMath.atan2() are required to give the same results as the reference implementation.
It's interesting to note that StrictMath.atan2() doesn't include the same 2 ulp comment as Math.atan2(). While it would be nice if it repeated fdlibm's "below one ulp" comment explicitly, I interpret the absence of this comment to mean StrictMath's implementation does not need to include that caveat - it will always be below one ulp.
tl;dr if you need precise results or stable results cross-platform use StrictMath. Math trades off precision for speed.
Edit: at first I thought this can be answered using "results must be semi-monotonic" requirement from the javadoc, but it actually can't be applied, so I re-wrote the answer.
Almost everything I can say is already covered by dimo414's answer. I just want to add: when using Math.atan2 on the same platform or even when using StrictMath.atan2 there is no formal guarantee (from the documentation) that atan2(y, x) == atan2(y * k, x * k). Sure, StrictMath's implementation actually uses y / x, so when y / x is precisely the same double value, the results will be equal (here I reasonably imply that function is deterministic), but keep it in mind.
Answering that part about int parameters: int holds 32 bits (actually, more like 31 bits plus one bit for sign) and can be represented by double type without any loss of precision, so no new problems there.
And the difference you described in the question (for non-overflowing long values) is caused by a loss of precision when converting long values to double, it has nothing to do with Math.atan2 itself, and it happens before the function is even called. double type can hold only 53 bits of mantissa, but in your case a * k requires 54 bits, so it is rounded to the nearest number a double can represent (b * k is okay though, it requires only 52 bits):
long a = 959786689;
long b = 363236985;
long k = 9675271;
System.out.println(a * k);
System.out.println((double) (a * k));
System.out.println((long) (double) (a * k));
System.out.println((long) (double) (a * k) == a * k);
System.out.println(b * k);
System.out.println((double) (b * k));
System.out.println((long) (double) (b * k));
System.out.println((long) (double) (b * k) == b * k);
Output:
9286196318267719
9.28619631826772E15
9286196318267720
false
3514416267097935
3.514416267097935E15
3514416267097935
true
And to address the example from the comment:
We have double a = 1.02551177480084, b = 1.12312341356234, k = 5;. In this case none of a, b, a * k, b * k can be represented as double without loss of precision. I'll use BigDecimal to demonstrate it, because it can show the true (not rounded) value of double:
double a = 1.02551177480084;
System.out.println("a is " + new BigDecimal(a));
System.out.println("a * 5 is " + new BigDecimal(a * 5));
System.out.println("a * 5 should be " + new BigDecimal(a).multiply(new BigDecimal("5")));
outputs
a is 1.0255117748008399924941613789997063577175140380859375
a * 5 is 5.12755887400420018451541182002983987331390380859375 // precision loss here
a * 5 should be 5.1275588740041999624708068949985317885875701904296875
and the difference can be clearly seen (same can be done with b instead of a).
There is a more simple test (since atan2() essentially uses a/b):
double a = 1.02551177480084, b = 1.12312341356234, k = 5;
System.out.println(a / b == (a * k) / (b * k));
outputs
false