是否有任何可用的函数定义,如, , , , sqrt()
(sin()
这些cos()
来自tan()
math.h /cmath)?log()
exp()
我只是想知道它们是如何工作的。
是否有任何可用的函数定义,如, , , , sqrt()
(sin()
这些cos()
来自tan()
math.h /cmath)?log()
exp()
我只是想知道它们是如何工作的。
这是一个有趣的问题,但是除非您碰巧知道使用的方法,否则阅读高效库的资源不会让您走得太远。
这里有一些提示可以帮助您理解经典方法。我的信息绝不准确。以下方法仅为经典方法,具体实现可以使用其他方法。
sincos
函数。atan2
是通过调用sincos
和一点逻辑来计算的。这些函数是复杂算术的构建块。每个实现可能不同,但您可以从 glibc(GNU C 库)源代码中查看一个实现。
编辑:谷歌代码搜索已下线,所以我的旧链接无处可去。
glibc 的数学库的源代码位于此处:
看看如何glibc
实现各种数学函数,充满魔力、逼近和汇编。
一定要看看fdlibm源代码。它们很好,因为 fdlibm 库是自包含的,每个函数都有详细的文档说明,并详细解释了所涉及的数学,并且代码非常清晰易读。
看过很多数学代码后,我建议不要看 glibc - 代码通常很难理解,并且很大程度上取决于 glibc 的魔法。FreeBSD 中的数学库更容易阅读,尽管有时速度较慢(但不是很多)。
对于复杂函数,主要困难是边界情况——正确的 nan/inf/0 处理对于实际函数来说已经很困难了,但对于复杂函数来说却是一场噩梦。C99标准定义了很多corner case,有些函数很容易就有10-20个corner case。您可以查看最新的C99 标准文档的附件 G以获得一个想法。long double 也有一个困难,因为它的格式不是标准化的——根据我的经验,你应该预料到 long double 会有很多错误。希望即将到来的具有扩展精度的修订版 IEEE754 将改善这种情况。
大多数现代硬件都包括非常有效地实现这些功能的浮点单元。
用法:根(数字,根,深度)
示例: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
这些几乎总是作为系统调用实现的。如果您想查看源代码,则需要访问操作系统源代码,这意味着您需要查看像 Linux 或 BSD 这样的开源操作系统。