C 如何计算 sin() 和其他数学函数? [英] How does C compute sin() and other math functions?

查看:26
本文介绍了C 如何计算 sin() 和其他数学函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在研究 .NET 反汇编和 GCC 源代码,但似乎无法在任何地方找到 sin() 和其他数学函数的实际实现......它们似乎总是引用别的东西.

I've been poring through .NET disassemblies and the GCC source code, but can't seem to find anywhere the actual implementation of sin() and other math functions... they always seem to be referencing something else.

谁能帮我找到它们?我觉得 C 运行的所有硬件不太可能支持硬件中的触发函数,所以必须有一个软件算法某处,对吧?

Can anyone help me find them? I feel like it's unlikely that ALL hardware that C will run on supports trig functions in hardware, so there must be a software algorithm somewhere, right?

我知道可以计算函数的几种方法,并且为了好玩,我已经编写了自己的例程来使用泰勒级数计算函数.我很好奇生产语言的真实性如何,因为我的所有实现总是慢几个数量级,尽管我认为我的算法非常聪明(显然它们不是).

I'm aware of several ways that functions can be calculated, and have written my own routines to compute functions using taylor series for fun. I'm curious about how real, production languages do it, since all of my implementations are always several orders of magnitude slower, even though I think my algorithms are pretty clever (obviously they're not).

推荐答案

在 GNU libm 中,sin 的实现依赖于系统.因此,您可以在 sysdeps.

In GNU libm, the implementation of sin is system-dependent. Therefore you can find the implementation, for each platform, somewhere in the appropriate subdirectory of sysdeps.

一个目录包含一个由 IBM 提供的 C 实现.自 2011 年 10 月以来,这是在典型的 x86-64 Linux 系统上调用 sin() 时实际运行的代码.它显然比 fsin 汇编指令快.源代码:sysdeps/ieee754/dbl-64/s_sin.c,寻找__sin (double x).

One directory includes an implementation in C, contributed by IBM. Since October 2011, this is the code that actually runs when you call sin() on a typical x86-64 Linux system. It is apparently faster than the fsin assembly instruction. Source code: sysdeps/ieee754/dbl-64/s_sin.c, look for __sin (double x).

这段代码非常复杂.没有任何软件算法能在 x 值的整个范围内尽可能快且准确,因此该库实现了几种不同的算法,其首要任务是查看 x 并决定使用哪种算法.

This code is very complex. No one software algorithm is as fast as possible and also accurate over the whole range of x values, so the library implements several different algorithms, and its first job is to look at x and decide which algorithm to use.

  • x 非常非常接近 0 时,sin(x) == x 是正确答案.

  • When x is very very close to 0, sin(x) == x is the right answer.

再进一步,sin(x) 使用熟悉的泰勒级数.但是,这仅在 0 附近准确,所以...

A bit further out, sin(x) uses the familiar Taylor series. However, this is only accurate near 0, so...

当角度大于 7° 时,将使用不同的算法,计算 sin(x) 和 cos(x) 的泰勒级数近似值,然后使用预计算表中的值来优化近似值.

When the angle is more than about 7°, a different algorithm is used, computing Taylor-series approximations for both sin(x) and cos(x), then using values from a precomputed table to refine the approximation.

当 |x|> 2,上述算法都不起作用,因此代码首先计算一些接近 0 的值,该值可以提供给 sincos.

When |x| > 2, none of the above algorithms would work, so the code starts by computing some value closer to 0 that can be fed to sin or cos instead.

还有另一个分支来处理 x 是 NaN 或无穷大.

There's yet another branch to deal with x being a NaN or infinity.

这段代码使用了一些我以前从未见过的数字技巧,尽管我知道它们在浮点专家中可能是众所周知的.有时几行代码需要几段时间来解释.比如这两行

This code uses some numerical hacks I've never seen before, though for all I know they might be well-known among floating-point experts. Sometimes a few lines of code would take several paragraphs to explain. For example, these two lines

double t = (x * hpinv + toint);
double xn = t - toint;

(有时)用于将 x 减少到接近于 0 的值,该值与 x 相差多个 π/2,特别是 xn ×π/2.没有划分或分支的方式是相当聪明的.但根本没有评论!

are used (sometimes) in reducing x to a value close to 0 that differs from x by a multiple of π/2, specifically xn × π/2. The way this is done without division or branching is rather clever. But there's no comment at all!

较旧的 32 位版本的 GCC/glibc 使用了 fsin 指令,这对于某些输入来说非常不准确.有一篇引人入胜的博客文章说明只需两行代码.

Older 32-bit versions of GCC/glibc used the fsin instruction, which is surprisingly inaccurate for some inputs. There's a fascinating blog post illustrating this with just 2 lines of code.

fdlibm 在纯 C 中对 sin 的实现比 glibc 简单得多,并且有很好的注释.源代码:fdlibm/s_sin.cfdlibm/k_sin.c

fdlibm's implementation of sin in pure C is much simpler than glibc's and is nicely commented. Source code: fdlibm/s_sin.c and fdlibm/k_sin.c

这篇关于C 如何计算 sin() 和其他数学函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆