我一直在钻研.NET分解和GCC源代码,但似乎在任何地方都找不到sin()
和其他数学函数的实际实现...他们似乎总是在引用其他东西.
有人能帮我找到他们吗?我觉得不太可能所有运行C的硬件都支持硬件中的触发功能,所以一定有软件算法somewhere,对吧?
我知道计算函数的几种方法,为了好玩,我编写了自己的 routine ,使用泰勒级数计算函数.我对生产语言的真实性很好奇,因为我所有的实现总是慢几个数量级,尽管我认为我的算法非常聪明(显然不是).
我一直在钻研.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.c和fdlibm/k_sin.c