cmath中的平方、sin、cos、pow等的定义

问题描述 投票:33回答:8

是否有任何函数的定义,如 sqrt(), sin(), cos(), tan(), log(), exp() (这些来自math.hcmath)可用吗?

我只是想知道它们是如何工作的。

c++ c math cmath definitions
8个回答
65
投票

这是一个有趣的问题,但阅读高效库的来源不会让你走得很远,除非你碰巧知道使用的方法。

这里有一些指针可以帮助你了解经典的方法。我的信息绝非准确。以下方法只是经典的方法,特定的实现可以使用其他方法。

  • 查找表经常被使用
  • 三角函数通常通过 CORDIC 算法(在CPU上或用库)。请注意,通常正弦和余弦是一起计算的,我一直很奇怪,为什么标准的C库不提供一个? sincos 函数。
  • 平方根使用 牛顿法 与一些巧妙的实现技巧:你可能会在网络上的某个地方找到 Quake 源代码的摘录,其中有一个令人头疼的 1 sqrt(x) 实现。
  • 指数和对数使用exp(2^n x) = exp(x)^(2^n)和log2(2^n x) = n + log2(x)来有一个接近于零的参数(对数为1),并使用有理函数近似(通常是 近似值). 请注意,这个完全相同的技巧可以让你得到矩阵指数和对数。根据@Stephen Canon的说法,现代的实现偏重于泰勒展开,而不是有理函数近似,除法比乘法慢得多。
  • 其他函数可以从这些函数中推导出来。实现可以提供专门的例程。
  • pow(x, y) = exp(y * log(x)), 所以 pow 是 当y是一个整数时使用。
  • hypot(x, y) = abs(x) sqrt(1 + (yx)^2) if x > y (hypot(y, x) otherwise)) 以避免溢出。atan2 是通过调用 sincos 和一点逻辑。这些函数是复数运算的基础。
  • 关于其他的超越函数(gamma, erf, bessel, ...), 请参考优秀的书籍 数学食谱,第三版 的一些想法。好的'老 Abramowitz & Stegun; 也是有用的。有一个新的版本在 http:/dlmf.nist.gov.
  • 像Chebyshev近似、持续分数膨胀(实际上与Padé近似有关)或幂级数经济化这样的技术在更复杂的函数中使用(例如,如果你碰巧读过erf、bessel或gamma的源代码)。我怀疑它们在裸机简单数学函数中是否有真正的用途,但谁知道呢。请参考Numerical Recipes来了解一下。

21
投票

每个实现可能都不一样,但你可以从glibc(GNU C库)的源代码中查看一个实现。

edit: Google Code Search 已经下线,所以我的旧链接无法找到。

glibc数学库的源代码在这里。

http:/sourceware.orggit?p=glibc.git;a=tree;f=math;h=3d5233a292f12cd9e9b9c67c3a114c64564d72ab;hb=HEAD。


7
投票

看看如何 glibc 实现了各种数学函数,充满了神奇,近似和汇编。


5
投票

一定要看一看 fdlibm 源。它们很好,因为fdlibm库是自成一体的,每个函数都有详细的数学解释,而且代码非常清晰易读。


4
投票

看了很多数学代码,我建议不要看glibc--代码往往相当难懂,而且很大程度上依赖于glibc的魔法。在这里,我建议大家不要看glibc--代码往往相当难懂,而且很大程度上依赖于glibc的魔法。FreeBSD中的数学库 更容易阅读,尽管有时会慢一些(但不会慢很多)。

对于复杂函数来说,主要的困难是边框情况--正确的naninf0处理对于实际函数来说已经很困难了,但对于复杂函数来说却是一场噩梦。C99标准定义了很多角案例,有些函数很容易就有10-20个角案例。你可以看一下最新的附件G C99标准文件 来了解一下。长双数也有困难,因为它的格式没有标准化--根据我的经验,你应该可以预料到长双数会有不少bug。希望即将到来的带有扩展精度的IEEE754修订版能够改善这种情况。


0
投票

大多数现代硬件都包含浮点单元,可以非常有效地实现这些功能。


-1
投票

使用方法:根(数,根,深度)

例子:根(16,2)==sqrt(16)==4。例子:根(16,2,2) == sqrt(sqrt(16)) == 2。例子:根(64,3) == 4。

在C#中实现:

double root(double number, double root, double depth = 1f)
{
    return Math.Pow(number, Math.Pow(root, -depth));
}

用途: Sqrt(Number,depth)

例子: Sqrt(16) == 4 例子: Sqrt(8,2) == sqrt(sqrt(8))

double Sqrt(double number, double depth = 1) return root(number,2,depth);

作者: Imk0tter


-16
投票

这些几乎都是作为系统调用来实现的。如果你想看源码,你需要访问操作系统的源码,这意味着你需要看一个开源的操作系统,比如Linux或BSD。

© www.soinside.com 2019 - 2024. All rights reserved.