三角函数的效率/速度

时间:2009-04-20 19:52:29

标签: performance geometry

在我正在制作的游戏中,我有两点,pt1和pt2,我想弄清楚它们之间的角度。在早先的计算中,我已经计算出了距离。显而易见的方法是在垂直距离(tan(theta)= opp / adj)上确定水平距离。

我想知道,因为我已经计算了距离,使用arcsine / arccosine与距离和dx或dy会更快吗?

另外,我可以在桌子上预先计算好吗?

9 个答案:

答案 0 :(得分:10)

除了关于过早优化的所有明智评论之外,让我们假设这是热点并做一个frigg'n benchmark

bar char

时间以纳秒为单位,按比例缩放以使系统之间的“acos”正常化 'acos'只假设单位半径为acos(adj),而'acos + div'表示acos(adj/hyp)

系统1是运行Mac OS X 10.6.4(gcc 4.2.1)的2.4GHz i5 系统2是运行Red Hat 7 Linux 2.6.28(gcc 4.1.2)的2.83GHz Core2 Quad 系统3是运行Ubuntu 10.04 2.6.32(gcc 4.4.3)的1.66GHz Atom N280 系统4是运行Ubuntu 10.04 2.6.32(gcc 4.4.3)的2.40GHz Pentium 4

总结:相对表现遍布地图。有时atan2更快,有时慢。非常奇怪的是,在某些系统中,使用除法执行acos比不使用除法更快。在您自己的系统上测试: - /

答案 1 :(得分:9)

我怀疑这里存在过早优化的风险。另外,请注意几何体。你的对立/相邻方法是直角三角形的属性,你实际拥有的是什么?

我假设您的点是平面的,因此对于一般情况,您可以隐式地将两个向量表示为原点(称为v1 v2),因此您的角度为

theta = arccos(dot(v1,v2)/(| v1 || v2 |))其中|。|是矢量长度。

加快速度(假设需要)将取决于很多事情。你知道矢量长度,还是必须计算它们?你可以多快在你的架构中做一个点积。 acos有多快?在某些时候,表查找(可能是插值)等技巧可能会有所帮助,但这会让你感到准确。

这是所有的权衡,但你的问题确实没有一般的答案。

[编辑:补充说明]

我想再次强调,经常玩“x是最快的”是一个带有现代cpus和编译器的杯子游戏。在测量并生成生成的代码之前,您不会知道。如果您在这个级别上真正关心它(希望是一小段代码),那么您可以详细了解您的系统正在做什么。但这是艰苦的。也许桌子很好。但也许你有快速的矢量计算和一个小缓存。等等都等于“它取决于”。抱歉,那个。另一方面,如果你没有达到你真正关心这段代码的程度......你可能根本就不应该在这个级别上考虑它。改正它。使它干净(这意味着抽象和代码)。然后担心开销。

答案 2 :(得分:6)

如果您要执行多次次,请在表格中预先计算。这种方式的表现要好得多。

答案 3 :(得分:5)

这里有很多好的答案。

顺便说一句,如果你使用Math.atan2,你可以得到一个完整的2π角度。

我会这样做,然后把它弄平。如果您不喜欢速度,如果示例显示您实际上大部分时间都在该代码中,而不是其他地方, 尝试用表查找替换它。如果你不需要精度接近1度,你可以使用一个非常小的表和插值。

另外,您可能想要记住该功能。为什么要重新计算你最近做过的事情?

补充:如果你使用一张桌子,它只需要覆盖0-45度的角度(它可以是硬编码的)。你可以通过对称来获得其他所有东西。

答案 4 :(得分:1)

从纯粹的速度角度来看,预先计算的表和最接近匹配的查找是最好的。当然,这需要一些开销,这取决于你需要角度的精细程度,但是如果你经常进行这种计算(或者在一个紧密的循环中),这将是非常值得的,因为它们将是昂贵的计算。

答案 5 :(得分:1)

先把它弄好! 然后进行剖析和优化。表格查找确实是一个很好的候选者,但在做任何花哨的事情之前一定要确定你的计算

答案 6 :(得分:1)

  1. 如果您对big-O表示法感兴趣,可能使用的所有方法都是O(1)。

  2. 如果您对最快的作品感兴趣,请进行测试。编写一个包装函数,一个调用您首选方法但可以轻松更改的函数,并使用它进行测试。确保您的应用程序花了相当多的时间来做这件事,这样您就不会浪费自己的时间。尝试任何方式发生在你身上。理想情况下,在多个不同的CPU上运行它。

  3. 我已经非常谨慎地预测在现代处理器上会花费多少时间。如果您需要速度,查找表曾经是答案,但您不知道先前对缓存的影响或者需要多长时间才能进行标准化和查找与在多长时间内执行触发器功能所需的时间特别的CPU。

答案 7 :(得分:0)

鉴于这是一场比赛,你可能会关心速度。查找表肯定是最快的,但您可以使用此方法交换速度的准确性。那么你必须准确满足要求吗?只有你能回答这个问题。在交易准确性之前,首先确定您是否有速度问题。使用数值方法计算所有三角函数(研究数值分析以了解更多信息)。有些trig函数比其他函数有更昂贵的方法,因为它们依赖于收敛速度更慢的系列,并且谁知道,您的计算机可能具有与其他计算机不同的这些函数实现。无论如何,您可以通过编写一些小程序来自己找出这些函数的成本,这些程序循环通过您想要的多次迭代,以您选择的增量,同时计算结果。然后你可以选择最快的方法。

答案 8 :(得分:0)

虽然其他人提到你几乎肯定会陷入过早优化的陷阱是非常正确的,当他们说三角函数是O(1)时,他们并没有讲述整个故事。

大多数三角函数实现实际上是输入函数值中的O(N)。这是因为trig函数最有效地计算在像[0,2π]这样的小间隔上(或者,对于最佳实现,甚至是这个区间的更小部分,但是这一点足以解释事物)。所以算法在伪Python中看起来像这样:

def Cosine_0to2Pi(x):
    #a series approximation of some kind, or CORDIC, or perhaps a table
    #this function requires 0 <= x < 2Pi

def MyCosine(x):
    if x < 0:
         x = -x
    while x >= TwoPi:
         x -= TwoPi
    return Cosine_0to2Pi(x)

即使像x87 FSINCOS这样的微编码CPU指令也会在内部执行类似的操作。所以trig函数,因为它们是周期性的,通常花费O(N)时间来减少参数。但有两点需要注意:

  1. 如果你必须从trig函数的主域中计算出大量的值,那么你的数学可能没有经过深思熟虑。
  2. Big-O符号隐藏了一个常数因素。参数减少具有非常小的常数因子,因为它很简单。因此,对于几乎每个输入,O(1)部分将主导O(N)部分。