atan
和atan2
在C++中有什么区别?
从学校数学我们知道正切的定义
tan(α) = sin(α) / cos(α)
我们根据提供给函数的角度将四象限区分为四个部分。 sin
,cos
和 tan
的符号具有以下关系(在忽略精确的 π/2
的倍数的情况下):
Quadrant Angle sin cos tan
-------------------------------------------------
I 0 < α < π/2 + + +
II π/2 < α < π + - -
III π < α < 3π/2 - - +
IV 3π/2 < α < 2π - + -
如果 tan(α)
的值为正数,我们无法区分这个角度是来自第一象限还是第三象限;如果是负数,则可能来自第二象限或第四象限。因此按照惯例,atan()
返回来自第一或第四象限的角度(即 -π/2 <= atan() <= π/2
),而不考虑切线函数的原始输入。
要获取完整信息,我们必须不使用除法 sin(α) / cos(α)
的结果,而是必须单独查看正弦和余弦的值。这就是 atan2()
的作用。它同时获取正弦和余弦值,并且在余弦值为负时将 π
加到 atan()
的结果中,以解决所有四个象限的问题。
注意:atan2(y, x)
函数实际上需要一个 y
和一个 x
参数,它们是向量在 y 轴和 x 轴上的投影,长度为 v
,角度为 α
。
y = v * sin(α)
x = v * cos(α)
给出了关系
y/x = tan(α)
结论:atan(y/x)
保留了一些信息,只能假设输入来自第一或第四象限。相比之下,atan2(y,x)
获取了所有数据,因此可以解析正确的角度。
实际值以弧度为单位,但如果要按角度解释它们,则应该:
atan
= 给出介于-90和90之间的角度值atan2
= 给出介于-180和180之间的角度值对于我的工作--计算导航中的各种角度(如航向和方位),atan2
在大多数情况下都能胜任。
还有一件需要说明的事情是使用表达式atan(y / x)
计算正切时,当x
等于0或接近0时,atan2
更加稳定。
atan(x) 返回 x 的反正切值,以弧度表示。
atan2(y,x) 返回 y/x 的反正切值的主值,以弧度表示。
请注意,由于符号的不确定性,一个函数不能仅通过其正切值(仅使用 atan)确定角落落在哪个象限。如果需要确定象限,可以使用 atan2。
(-pi,pi]
,但 atan2 的范围为 [-pi,pi]
,因此由于 atan2(-0.0,x)
对于 x<0
包括另一个分支的一个额外值 -pi
。 - Z boson我猜主要问题是想搞清楚:“什么时候应该使用其中一个”,或者“应该使用哪个”,或者“我是否正在使用正确的函数”?
重要的一点是,atan 函数只适合用于正值来构建右上方向的曲线,比如时间-距离向量。在这种情况下,零始终位于左下角,物体只能向右上方移动,移动速度可能快或慢。atan 函数不返回负数,因此你不能通过添加/减去其结果来沿着屏幕的四个方向跟踪物体。
而 atan2 函数适用于以原点为中心的坐标系,物体可以向后或向下移动。在屏幕表示中应该使用 atan2 函数,因为曲线的方向很重要。因此,atan2 函数可以返回负数,因为它的零点在中心,其结果可用于沿着四个方向跟踪物体。
p=y/x
,仍然可以使用atan2(p,1)
。 - Mark Ransomatan
一样的象限信息。 - Mark RansomMehrwolf的回答是正确的,但这里有一个启发式方法可能会有所帮助:
如果您正在使用二维坐标系(通常用于编程反正切函数),那么一定要使用atan2。它将提供完整的2π角度范围,并为您处理x坐标中的零值。
另一种说法是,atan(y/x)几乎总是错误的。仅在参数无法视为y/x时使用atan。
-pi
< atan2(y,x)
<pi
-pi/2
< atan(y/x)
< pi/2
//它不考虑象限。0
和2*pi
之间的方向(如高中数学),我们需要使用atan2,并对负值添加2*pi
以获得最终结果在0
和2*pi
之间。System.out.println(Math.atan2(1,1)); //pi/4 in the 1st quarter
System.out.println(Math.atan2(1,-1)); //(pi/4)+(pi/2)=3*(pi/4) in the 2nd quarter
System.out.println(Math.atan2(-1,-1 ));//-3*(pi/4) and it is less than 0.
System.out.println(Math.atan2(-1,-1)+2*Math.PI); //5(pi/4) in the 3rd quarter
System.out.println(Math.atan2(-1,1 ));//-pi/4 and it is less than 0.
System.out.println(Math.atan2(-1,1)+2*Math.PI); //7*(pi/4) in the 4th quarter
System.out.println(Math.atan(1 ));//pi/4
System.out.println(Math.atan(-1 ));//-pi/4
-π/2 <= atan() <= π/2
的反正切函数实际上包括来自第二象限的一个点(pi/2
)。 - Z boson