我一直在研究。net反汇编和GCC源代码,但似乎在任何地方都找不到sin()和其他数学函数的实际实现…他们似乎总是在引用别的东西。
有人能帮我找到他们吗?我觉得不太可能运行C语言的所有硬件都支持三角函数,所以一定有软件算法,对吧?
我知道有几种方法可以计算函数,并且为了好玩,我写了自己的例程来使用泰勒级数计算函数。我很好奇生产语言是如何做到这一点的,因为我的所有实现总是慢几个数量级,尽管我认为我的算法非常聪明(显然不是)。
我一直在研究。net反汇编和GCC源代码,但似乎在任何地方都找不到sin()和其他数学函数的实际实现…他们似乎总是在引用别的东西。
有人能帮我找到他们吗?我觉得不太可能运行C语言的所有硬件都支持三角函数,所以一定有软件算法,对吧?
我知道有几种方法可以计算函数,并且为了好玩,我写了自己的例程来使用泰勒级数计算函数。我很好奇生产语言是如何做到这一点的,因为我的所有实现总是慢几个数量级,尽管我认为我的算法非常聪明(显然不是)。
当前回答
如果你想犯罪
__asm__ __volatile__("fsin" : "=t"(vsin) : "0"(xrads));
如果你想的话,因为
__asm__ __volatile__("fcos" : "=t"(vcos) : "0"(xrads));
如果你想要根号方根
__asm__ __volatile__("fsqrt" : "=t"(vsqrt) : "0"(value));
那么,既然机器指令可以做到,为什么还要使用不准确的代码呢?
其他回答
计算正弦/余弦/正切其实很容易通过代码使用泰勒级数来实现。自己写一个只需5秒钟。
整个过程可以用这个方程来概括:
下面是我为C语言写的一些例程:
double _pow(double a, double b) {
double c = 1;
for (int i=0; i<b; i++)
c *= a;
return c;
}
double _fact(double x) {
double ret = 1;
for (int i=1; i<=x; i++)
ret *= i;
return ret;
}
double _sin(double x) {
double y = x;
double s = -1;
for (int i=3; i<=100; i+=2) {
y+=s*(_pow(x,i)/_fact(i));
s *= -1;
}
return y;
}
double _cos(double x) {
double y = 1;
double s = -1;
for (int i=2; i<=100; i+=2) {
y+=s*(_pow(x,i)/_fact(i));
s *= -1;
}
return y;
}
double _tan(double x) {
return (_sin(x)/_cos(x));
}
像正弦和余弦这样的函数是在微处理器内部的微码中实现的。例如,英特尔芯片就有相应的组装指令。C编译器将生成调用这些汇编指令的代码。(相反,Java编译器不会。Java在软件而不是硬件中计算三角函数,因此运行速度要慢得多。)
芯片不使用泰勒级数来计算三角函数,至少不完全是这样。首先,他们使用CORDIC,但他们也可能使用一个短的泰勒级数来优化CORDIC的结果,或者用于特殊情况,例如在非常小的角度下以相对较高的精度计算正弦。有关更多解释,请参阅StackOverflow的回答。
正如许多人指出的那样,它依赖于实现。但就我对你的问题的理解而言,你对数学函数的真正软件实现感兴趣,但只是没有找到一个。如果是这样的话,那么你是这样的:
从http://ftp.gnu.org/gnu/glibc/下载glibc源代码 查看位于解包的glibc根\sysdeps\ieee754\dbl-64文件夹中的文件dosincosc 类似地,您可以找到其余数学库的实现,只需查找具有适当名称的文件
您也可以看看扩展名为.tbl的文件,它们的内容只不过是以二进制形式的不同函数的预计算值的巨大表格。这就是为什么实现如此之快:而不是计算他们使用的任何级数的所有系数,他们只是做一个快速查找,这要快得多。顺便说一下,他们确实用裁缝级数来计算正弦和余弦。
我希望这能有所帮助。
库函数的实际实现取决于特定的编译器和/或库提供程序。不管它是用硬件还是软件,不管它是不是泰勒展开,等等,都会有所不同。
我意识到这完全没有帮助。
是的,也有计算罪恶的软件算法。基本上,用数字计算机计算这些东西通常是用数值方法来完成的,比如近似表示函数的泰勒级数。
数值方法可以将函数近似到任意精度,因为浮点数的精度是有限的,所以它们非常适合这些任务。