C++中的atan和atan2有什么区别?

220

atanatan2在C++中有什么区别?

11个回答

407

从学校数学我们知道正切的定义

tan(α) = sin(α) / cos(α)

我们根据提供给函数的角度将四象限区分为四个部分。 sincostan 的符号具有以下关系(在忽略精确的 π/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) 获取了所有数据,因此可以解析正确的角度。


8
一个小细节,范围为-π/2 <= atan() <= π/2的反正切函数实际上包括来自第二象限的一个点(pi/2)。 - Z boson

168

std::atan2允许计算所有四个象限的反正切值。而std::atan只能计算第一和第四象限的反正切值。


46

实际值以弧度为单位,但如果要按角度解释它们,则应该:

  • atan = 给出介于-90和90之间的角度值
  • atan2 = 给出介于-180和180之间的角度值

对于我的工作--计算导航中的各种角度(如航向和方位),atan2 在大多数情况下都能胜任。


1
这里最直观的答案。 - arkon

32

还有一件需要说明的事情是使用表达式atan(y / x)计算正切时,当x等于0或接近0时,atan2更加稳定。


有趣,你有这方面的来源吗?这是普遍适用还是只针对C++? - Gerard

16

atan(x) 返回 x 的反正切值,以弧度表示。

atan2(y,x) 返回 y/x 的反正切值的主值,以弧度表示。

请注意,由于符号的不确定性,一个函数不能仅通过其正切值(仅使用 atan)确定角落落在哪个象限。如果需要确定象限,可以使用 atan2。


主值范围为 (-pi,pi],但 atan2 的范围为 [-pi,pi],因此由于 atan2(-0.0,x) 对于 x<0 包括另一个分支的一个额外值 -pi - Z boson

10

我猜主要问题是想搞清楚:“什么时候应该使用其中一个”,或者“应该使用哪个”,或者“我是否正在使用正确的函数”?

重要的一点是,atan 函数只适合用于正值来构建右上方向的曲线,比如时间-距离向量。在这种情况下,零始终位于左下角,物体只能向右上方移动,移动速度可能快或慢。atan 函数不返回负数,因此你不能通过添加/减去其结果来沿着屏幕的四个方向跟踪物体。

而 atan2 函数适用于以原点为中心的坐标系,物体可以向后或向下移动。在屏幕表示中应该使用 atan2 函数,因为曲线的方向很重要。因此,atan2 函数可以返回负数,因为它的零点在中心,其结果可用于沿着四个方向跟踪物体。


5
考虑一个直角三角形。我们将斜边标记为r,水平边标记为y,竖直边标记为x。所感兴趣的角度α是x和r之间的角度。
C++中,atan2(y,x)将给出以弧度表示的角度α的值。 如果我们只知道或感兴趣的是y/x而不是y和x分别,则使用atan。因此,如果p = y/x,则要获取α,我们将使用atan(p)。
您不能使用atan2来确定象限,只有在您已经知道自己处于哪个象限时才能使用atan2!特别地,正x和正y意味着第一象限,正y和负x意味着第二象限,依此类推。 atan或atan2本身仅返回正数或负数,没有其他内容。

4
如果您只有p=y/x,仍然可以使用atan2(p,1) - Mark Ransom
@MarkRansom 当然可以,但是它的速度会稍微慢一些,并且不会返回比“atan”更多的信息,对吧? - Bill Kotsias
@BillKotsias 不确定为什么会变慢,但你说的没错,它也不包括象 atan 一样的象限信息。 - Mark Ransom

2

Mehrwolf的回答是正确的,但这里有一个启发式方法可能会有所帮助:

如果您正在使用二维坐标系(通常用于编程反正切函数),那么一定要使用atan2。它将提供完整的2π角度范围,并为您处理x坐标中的零值。

另一种说法是,atan(y/x)几乎总是错误的。仅在参数无法视为y/x时使用atan。


1
在atan2中,输出为:-pi < atan2(y,x) <pi
而在atan中,输出为:-pi/2 < atan(y/x) < pi/2 //它不考虑象限。
如果您想获得介于02*pi之间的方向(如高中数学),我们需要使用atan2,并对负值添加2*pi以获得最终结果在02*pi之间。
以下是Java源代码,以便清楚地解释它:
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

1

使用 atan2 函数,您可以像 这里 所述一样确定象限。

如果您需要确定象限,则可以使用 atan2 函数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接