cmath 中 sqrt、sin、cos、pow 等的定义

发布于 2024-10-09 08:13:12 字数 181 浏览 5 评论 0原文

是否有诸如 sqrt()sin()cos()tan() 等函数的定义、log()exp()(这些来自 math.h/cmath)可用吗?

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

Are there any definitions of functions like sqrt(), sin(), cos(), tan(), log(), exp() (these from math.h/cmath) available ?

I just wanted to know how do they work.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

终弃我 2024-10-16 08:13:13

这是一个有趣的问题,但是除非您碰巧知道所使用的方法,否则阅读高效库的源代码不会让您走得太远。

这里有一些指导可以帮助您理解经典方法。我的信息绝对不准确。下面的方法只是经典的方法,具体实现可以使用其他方法。

  • 查找表经常使用
  • 三角函数通常通过 CORDIC 算法(在 CPU 或与图书馆)。请注意,通常正弦和余弦是一起计算的,我一直想知道为什么标准 C 库不提供 sincos 函数。
  • 平方根使用 牛顿法 以及一些巧妙的实现技巧:您可能会在网络上找到某个地方Quake 源代码的摘录,其中包含令人难以置信的 1 / sqrt(x) 实现。
  • 指数和对数使用 exp(2^nx) = exp(x)^(2^n) 和 log2(2^nx) = n + log2(x) 使参数接近于零(对于 log 为 1)并使用有理函数近似(通常是 Padé 近似)。请注意,这个完全相同的技巧可以得到矩阵指数和对数。根据 @Stephen Canon 的说法,现代实现更倾向于泰勒展开式而不是有理函数逼近,其中除法比乘法慢得多。
  • 从这些函数可以推导出其他函数。实现可以提供专门的例程。
  • pow(x, y) = exp(y * log(x)),因此当 y 是整数时,使用 pow
  • hypert(x, y) = abs(x) sqrt(1 + (y/x)^2) 如果 x > y(否则为hypot(y, x))以避免溢出。 atan2 是通过调用 sincos 和一些逻辑来计算的。这些函数是复杂算术的构建块。
  • 对于其他超越函数(gamma、erf、bessel...),请参阅优秀书籍Numerical Recipes,第 3 版< /a> 一些想法。古老的Abramowitz & Stegun 也很有用。 http://dlmf.nist.gov/ 上有新版本。
  • 切比雪夫近似、连分式展开(实际上与 Padé 近似相关)或幂级数节约等技术用于更复杂的函数(例如,如果您碰巧阅读了 erf、bessel 或 gamma 的源代码)。我怀疑它们在裸机简单数学函数中是否有真正的用途,但谁知道呢。有关概述,请参阅数值食谱。

This is an interesting question, but reading sources of efficient libraries won't get you very far unless you happen to know the method used.

Here are some pointers to help you understand the classical methods. My information is by no means accurate. The following methods are only the classical ones, particular implementations can use other methods.

  • Lookup tables are frequently used
  • Trigonometric functions are often implemented via the CORDIC algorithm (either on the CPU or with a library). Note that usually sine and cosine are computed together, I always wondered why the standard C library doesn't provide a sincos function.
  • Square roots use Newton's method with some clever implementation tricks: you may find somewhere on the web an extract from the Quake source code with a mind boggling 1 / sqrt(x) implementation.
  • Exponential and logarithms use exp(2^n x) = exp(x)^(2^n) and log2(2^n x) = n + log2(x) to have an argument close to zero (to one for log) and use rational function approximation (usually Padé approximants). Note that this exact same trick can get you matrix exponentials and logarithms. According to @Stephen Canon, modern implementations favor Taylor expansion over rational function approximation where division is much slower than multiplication.
  • The other functions can be deduced from these ones. Implementations may provide specialized routines.
  • pow(x, y) = exp(y * log(x)), so pow is not to be used when y is an integer
  • hypot(x, y) = abs(x) sqrt(1 + (y/x)^2) if x > y (hypot(y, x) otherwise) to avoid overflow. atan2 is computed with a call to sincos and a little logic. These functions are the building blocks for complex arithmetic.
  • For other transcendental functions (gamma, erf, bessel, ...), please consult the excellent book Numerical Recipes, 3rd edition for some ideas. The good'old Abramowitz & Stegun is also useful. There is a new version at http://dlmf.nist.gov/.
  • Techniques like Chebyshev approximation, continued fraction expansion (actually related to Padé approximants) or power series economization are used in more complex functions (if you happen to read source code for erf, bessel or gamma for instance). I doubt they have a real use in bare-metal simple math functions, but who knows. Consult Numerical Recipes for an overview.
感情旳空白 2024-10-16 08:13:13

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

编辑:Google 代码搜索已离线,因此我的旧链接无处可去。

glibc 数学库的源代码位于此处:

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

Every implementation may be different, but you can check out one implementation from glibc's (the GNU C library) source code.

edit: Google Code Search has been taken offline, so the old link I had goes nowhere.

The sources for glibc's math library are located here:

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

你是暖光i 2024-10-16 08:13:13

Have a look at how glibc implements various math functions, full of magic, approximation and assembly.

只是偏爱你 2024-10-16 08:13:13

一定要看看 fdlibm 源代码。它们很好,因为 fdlibm 库是独立的,每个函数都有详细的文档记录,并对所涉及的数学进行了详细的解释,并且代码非常清晰易读。

Definitely take a look at the fdlibm sources. They're nice because the fdlibm library is self-contained, each function is well-documented with detailed explanations of the mathematics involved, and the code is immensely clear to read.

沙沙粒小 2024-10-16 08:13:13

看了很多数学代码后,我建议不要看 glibc - 这些代码通常很难理解,并且很大程度上依赖于 glibc 的魔力。如果不知何故,FreeBSD 中的数学库 更容易阅读有时会慢一些(但不会慢很多)。

对于复杂函数,主要困难是边界情况 - 正确的 nan/inf/0 处理对于实际函数来说已经很困难,但对于复杂函数来说则是一场噩梦。 C99标准定义了很多corner case,有些函数很容易就有10-20个corner case。您可以查看最新C99的附件G标准文档以获得一个想法。 long double 也有一个困难,因为它的格式不是标准化的 - 根据我的经验,long double 应该会出现很多错误。希望即将推出的具有扩展精度的 IEEE754 修订版能够改善这种情况。

Having looked a lot at math code, I would advise against looking at glibc - the code is often quite difficult to follow, and depends a lot on glibc magic. The math lib in FreeBSD is much easier to read, if somehow sometimes slower (but not by much).

For complex functions, the main difficulty is border cases - correct nan/inf/0 handling is already difficult for real functions, but it is a nightmare for complex functions. C99 standard defines many corner cases, some functions have easily 10-20 corner cases. You can look at the annex G of the up to date C99 standard document to get an idea. There is also a difficult with long double, because its format is not standardized - in my experience, you should expect quite a few bugs with long double. Hopefully, the upcoming revised version of IEEE754 with extended precision will improve the situation.

百合的盛世恋 2024-10-16 08:13:13

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

Most modern hardware include floating point units that implement these functions very efficiently.

原谅过去的我 2024-10-16 08:13:13

用法: root(number,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(Number,深度)

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

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

作者:Imk0tter

Usage: root(number,root,depth)

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

Implementation in C#:

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

Usage: Sqrt(Number,depth)

Example: Sqrt(16) == 4
Example: Sqrt(8,2) == sqrt(sqrt(8))

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

By: Imk0tter

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文