我一直在钻研.NET分解和GCC源代码,但似乎在任何地方都找不到sin()和其他数学函数的实际实现...他们似乎总是在引用其他东西.

有人能帮我找到他们吗?我觉得不太可能所有运行C的硬件都支持硬件中的触发功能,所以一定有软件算法somewhere,对吧?


我知道计算函数的几种方法,为了好玩,我编写了自己的 routine ,使用泰勒级数计算函数.我对生产语言的真实性很好奇,因为我所有的实现总是慢几个数量级,尽管我认为我的算法非常聪明(显然不是).

推荐答案

在GNU libm中,sin的实现依赖于系统.因此,您可以在相应的子目录sysdeps中找到每个平台的实现.

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

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

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

  • 再往前一点,sin(x)使用熟悉的泰勒级数.然而,这只在0附近精确,所以...

  • 当Angular 大于约7°时,使用不同的算法,计算sin(X)和cos(X)的泰勒级数近似,然后使用预计算表中的值改进近似.

  • 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或无穷大.

这段代码使用了一些我以前从未见过的数值技巧,尽管据我所知,它们在浮点专家中可能很出名.有时几行代码需要几个段落才能解释.举个例子,这两条线

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

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指令,对于某些输入来说,这是令人惊讶的不准确.有一张fascinating blog post illustrating this with just 2 lines of code美元的钞票.

fdlibm用纯C实现sin比glibc简单得多,而且注释很好.源代码:fdlibm/s_sin.cfdlibm/k_sin.c

C++相关问答推荐

在C、Linux中同步进程

问关于C中的指针和数组

CC crate 示例不会与C函数链接

try 使用sigqueue函数将指向 struct 体的指针数据传递到信号处理程序,使用siginfo_t struct 体从一个进程传递到另一个进程

如何正确地索引C中的 struct 指针数组?

在#include中使用C宏变量

变量>;-1如何在C中准确求值?

如何在C客户端应用程序的ClientHello消息中添加自定义扩展?

为什么中断函数会以这种方式影响数组?

为什么指针运算会产生错误的结果?

For循环中的变量行为不符合预期.[C17]

处理EPOLL_WAIT中的接收数据和连接关闭信号

C";中的ANN运行时判断失败#2-变量outputLayer;周围的堆栈已损坏.运行后出错

C:Assignment中的链表赋值从指针目标类型中丢弃‘const’限定符

为什么我的半数组测试和奇数组测试不起作用?(我使用Assert进行调试)

为什么会导致分段故障?(C语言中的一个程序,统计文件中某个单词的出现次数)

挥发性语义的形式化理解

我可以使用Windows SDK';s IN6_IS_ADDR_LOOPBACK等,尽管没有文档?

如何用用户输入的多个字符串填充数组?

如何在 C 中的 Postgres 函数的表中 for 循环