三角函数的计算成本

21

可能重复:
三角函数是如何工作的?

计算Sin、Cos、Tan和Atan等三角函数的实际方法是什么?

我认为我在我的代码中找到了一种优化方法,可以避免使用任何这些函数,而是以斜率为基础来解决问题,这意味着在上述三角函数的位置上使用一些除法运算。但我想更多地了解这些三角函数的计算方法,以便我可以比较我的新代码(从基本数学运算次数的角度)。或者,我可能只是找到了一种更迂回的做法,或者更糟糕的是,引入了一种不太有效的方法。

使用C++和Python,但我认为这与语言无关,因为数学运算成本相对于最原始的操作。


1
如果你非常关心这个问题,你可以预先计算所需的值(在应用程序启动时或将它们保存在文本文件中并加载),将它们存储在表格中,然后只需要查找即可。 - FrustratedWithFormsDesigner
1
我并不是在这个特定的情况下,这更多是关于理解我一直不清楚的事情。 - ack
@AK:在这种情况下,您可能想看一下这个问题:https://dev59.com/FXRC5IYBdhLWcg3wS_EF - FrustratedWithFormsDesigner
8个回答

9

你需要对代码进行性能分析!

对于这个问题,你需要自己进行性能分析。根据我的结果,三角函数大约需要100纳秒,而除法则需要20纳秒。这些数据可以很容易地转换为答案。但是最重要的是,在你自己的硬件上进行性能分析,这样你就可以获得准确的答案和有关你系统的知识。


6
当然,那样做可以完成工作,但它并不能真正告诉我为什么更快。 - ack

6

现代x86处理器在其指令集中包含三角函数,但执行需要很多个周期。因此,如果你使用这样的处理器,并且代码中没有依赖关系(即不需要一个sin计算的结果才能开始下一个计算),那么直接使用sin和cos可能不会比较快,因为它们将被完全流水线化,达到每个周期1个的有效速率。


5
我认为完整的三角函数比每个周期慢得多。在等待三角函数完成时,您可能可以做其他事情,但是三角运算本身无法以这种方式进行流水线操作。 - comingstorm
因此,您可以通过使用近似值来加速处理速度,也可能不行 - 这取决于您的应用程序以及您可以接受多少近似值。 - comingstorm
此外,重新调整您的数学公式以避免三角函数有时可以大大加快和简化您的代码,这完全独立于三角函数本身的成本。 - comingstorm
C语言中的sin()函数通常不会被编译成x87的fsin指令,大多数编译器都是这样。这些指令是高度微代码化的,例如在Skylake上需要53到105个微操作码(https://agner.org/optimize),吞吐量可能与延迟一样糟糕(非流水线)。在Nehalem(您发布此答案时的当前版本)上,`fsin`需要100个微操作码,延迟和吞吐量均为40到100个周期。而且许多数学库已经不再使用它。 - Peter Cordes

2

(Codekaizen):如今,大多数三角函数都是以查找表的形式实现的。

嗯...由于大多数三角函数需要双精度参数,因此查找值并不实用。我相信大多数人会在两侧查找整数,然后从那里进行插值计算(即Sin(5.279)是从Sin(5)到Sin(6)的27.9%)。这比直接计算价值少了一些工作,但仍需要相当数量的计算。


我从未见过一个表格,其中存储了每个不同的双精度值。 - codekaizen
@codekaizen:我也没有。我的意思是,你的回答实现了你有那个东西的功能。 - James Curran
我看不出你如何从逻辑上推断出那个结论。给定一张表格并不意味着所有可能的值都被包含在内。稍加思考就会发现,覆盖所有值的表格是不合理的。 - codekaizen
你有什么证据支持这个吗?我非常怀疑。这意味着例如数值计算 sin(x) 的二阶导数将会是0!如果你将x映射到[0..pi/4]之间的一个值,计算泰勒近似会非常快速收敛。 - Niki
这并不糟糕 - 首先由于对称性,你只需要0-45度。而且你可以使用恒等式从sin(a)+ sin(b)计算出sin(a + b),因此你只需要存储非常稀疏的表格。 - Martin Beckett

0

现在大多数三角函数都是以查找表的形式实现的。


0

从我的经验来看,三角函数非常快,并且它们中的大多数都是作为查找表实现的...也就是说,一些除法和除以零检查可能比调用三角函数更慢。


比除法更快?我猜那是在比较两个完全不同的东西,这就成为了架构细节的问题...如果它真的是一个查找表,那么这意味着我的旧方法使用纯三角函数会更快,对吗? - ack
我认为是这样的,是的。查找表需要内存访问,除非您在某个缓存级别上得到了命中。 - aioobe
@aioobe,我很确定许多系统的查找表是在芯片上实现的,因此不需要进行内存访问。我认为几年前臭名昭著的奔腾数学问题的原因就是查找表中出现了错误。 - Jeffrey L Whitledge
@Jeffrey,你有那个数学问题的链接吗? - aioobe
@aioobe: http://en.wikipedia.org/wiki/Pentium_FDIV_bug : "...除法操作使用的查找表中缺少条目..." - timday
哦,对了,我以为你指的是三角查找方法中的错误,那听起来不太熟悉。现在我明白了 :-) - aioobe

0

你唯一真正的答案是"Profile."

很可能,如果这不是你代码中的瓶颈,它对性能没有任何明显的影响。


0

看一下glibc。它使用了几个不同的实现,其中一些(比如 sysdeps/ieee754/s_sin.c)看起来非常复杂,而其他的则使用汇编指令(比如sysdeps/x86_64/fpu/s_sincos.S)。如果没有一些测量,很难确定实际所需时间。


0

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