在cmath中sqrt,sin,cos,pow等的定义

时间:2010-12-27 19:10:44

标签: c++ c math cmath definitions

是否有sqrt()sin()cos()tan()log()exp()等函数的定义(这些来自数学。 h / cmath)可用?

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

8 个答案:

答案 0 :(得分:63)

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

以下是帮助您理解经典方法的一些指示。我的信息绝不准确。以下方法仅是经典方法,特定实现可以使用其他方法。

  • 经常使用查找表
  • 三角函数通常通过CORDIC算法实现(在CPU上或库中)。请注意,通常一起计算正弦和余弦,我总是想知道为什么标准C库不提供sincos函数。
  • 平方根使用Newton's method和一些聪明的实现技巧:你可以在网上的某个地方找到Quake源代码的摘录,其中包含1 / sqrt(x)实现的思维。
  • 指数和对数使用exp(2 ^ nx)= exp(x)^(2 ^ n)和log2(2 ^ nx)= n + log2(x)使参数接近于零(对于日志为1)并使用有理函数逼近(通常为Padé approximants)。请注意,这个完全相同的技巧可以获得矩阵指数和对数。根据@Stephen Canon的观点,现代实现有利于泰勒扩展而不是有理函数逼近,其中除法比乘法慢得多。
  • 其他功能可以从这些功能中推断出来。实现可以提供专门的例程。
  • pow(x,y)= exp(y * log(x)),因此当y是整数时,pow
  • hypot(x,y)= abs(x)sqrt(1 +(y / x)^ 2)如果x> y(否则为hypot(y,x))以避免溢出。通过调用atan2和一点逻辑来计算sincos。这些函数是复杂算术的构建块。
  • 对于其他超越函数(gamma,erf,bessel,...),请参阅优秀书籍Numerical Recipes, 3rd edition以获取一些想法。 good'old Abramowitz & Stegun也很有用。 http://dlmf.nist.gov/上有新版本。
  • Chebyshev近似,连续分数扩展(实际上与Padé近似相关)或幂级数节约等技术用于更复杂的函数(例如,如果您碰巧读取erf,bessel或gamma的源代​​码)。我怀疑它们在裸机简单的数学函数中有用,但是谁知道呢。有关概述,请参阅Numerical Recipes。

答案 1 :(得分:21)

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

编辑:Google代码搜索已脱机,因此旧链接无处可去。

glibc数学库的来源位于:

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

答案 2 :(得分:7)

了解glibc如何实现各种数学函数,充满魔力,逼近和装配。

答案 3 :(得分:5)

绝对要看看fdlibm来源。它们很好,因为fdlibm库是自包含的,每个函数都有详细记录,详细解释了所涉及的数学,并且代码非常清晰易读。

答案 4 :(得分:4)

看了很多数学代码,我建议不要看glibc - 代码通常很难遵循,并且很大程度上取决于glibc魔法。 math lib in FreeBSD更容易阅读,如果某种程度有时慢(但不是很多)。

对于复杂函数,主要困难是边界情况 - 正确的nan / inf / 0处理对于实际函数来说已经很难了,但它对于复杂函数来说是一场噩梦。 C99标准定义了许多角落情况,有些功能很容易有10-20个角落情况。您可以查看最新的C99 standard document附件G,以了解相关信息。还有一个困难的长双,因为它的格式没有标准化 - 根据我的经验,你应该期待相当多的错误与长双。希望即将推出的具有扩展精度的IEEE754修订版将改善这种情况。

答案 5 :(得分:0)

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

答案 6 :(得分:-1)

用法:root(数字,root,深度)

示例:root(16,2)== sqrt(16)== 4
示例:root(16,2,2)== sqrt(sqrt(16))== 2
示例:root(64,3)== 4

在C#中的实现

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

用法:Sqrt(数字,深度)

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

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

通过: Imk0tter

答案 7 :(得分:-15)

这些几乎总是作为系统调用实现。如果你想查看源代码,你需要访问操作系统源代码,这意味着你需要查看像Linux或BSD这样的开源操作系统。