[英]glibc uses kernel functions
我试图从glibc源代码中了解此方法:
26 #if LIBM_SVID_COMPAT
27 /* wrapper sqrtf */
28 float
29 __sqrtf (float x)
30 {
31 if (__builtin_expect (isless (x, 0.0f), 0) && _LIB_VERSION != _IEEE_)
32 return __kernel_standard_f (x, x, 126); /* sqrt(negative) */
33
34 return __ieee754_sqrtf (x);
35 }
36 libm_alias_float (__sqrt, sqrt)
37 #endif
据我了解,如果程序无法从glibc中找到sqrt
函数的有效实现,它将从内核调用硬件函数,即特定的机器函数。 这是正确的吗?
另外, libm_alias_float (__sqrt, sqrt)
是什么意思?
GNU C库的数学功能在“ glibc”源代码树中完全实现。 他们什么都不依赖操作系统内核。 在此上下文中,“内核”一词指的是计算内核,这是某些数学算法的核心,您可能想用手工优化的汇编语言编写该部分。
函数__kernel_standard_f
被错误命名。 它包含用于处理数学函数错误的通用代码。 最好将其命名为__math_domain_error
。 在这种情况下,当__sqrtf
的参数为负数时, __sqrtf
调用__kernel_standard_f
。 __kernel_standard_f
然后将把errno
为EDOM
,可能会调用SVID matherr
回调,并返回NaN。 (神秘代码126告诉__kernel_standard_f
该函数调用它,为什么。的执行__kernel_standard_f
是sysdeps/ieee754/k_standardf.c
和sysdeps/ieee754/k_standard.c
。)
条件_LIB_VERSION != _IEEE_
与是否启用POSIX和/或SVID数学错误处理有关; 现代数学算法实际上只希望在结果中查找NaN,而没有浪费库时间设置errno
或调用matherr
,因此有一种机制可以将后两者关闭。
如果__sqrtf
的参数不是负数,则尾部将调用__ieee754_sqrtf
,它执行平方根的实际计算。 glibc源代码树中有此功能的几种替代实现。 其仅C的通用版本在sysdeps/ieee754/flt-32/e_sqrtf.c
。 (即使按照glibc的标准,实现数学功能的文件的名称也是神秘的。我不必费心去理解它们,我只是find sysdeps -name '*sqrtf*'
或其他名称。)此功能还以逻辑开始检测一个负参数(也为零,无穷大和NaN)并返回适当的值,但它不会碰到errno
。 如果您想了解用于计算平方根的数学技术,请查看此文件。
如果您自己运行上述find
命令,则会发现其他几个名为e_sqrtf.c
文件; 这些都在以特定CPU命名的目录中,这些CPU的浮点单元对计算平方根具有硬件支持,因此sysdeps/x86_64/fpu/e_sqrt.c
读取
double
__ieee754_sqrt (double x)
{
double res;
asm ("sqrtsd %1, %0" : "=x" (res) : "xm" (x));
return res;
}
因为x86 sqrtsd
指令可以完成全部工作。
当为其中一个CPU进行构建时,Glibc的构建过程将选择这些文件之一,而不是通用C版本。 这种机制很复杂,并且没有完整记录,但是glibc手册的“维护”附录 ,特别是其“源布局”和“移植”部分,对它进行了详尽的介绍。
libm_alias_float (__sqrt, sqrt)
安排__sqrtf
也使用名称sqrtf
,但作为弱别名 。 为了符合标准,这是必需的。 如果您需要更多详细信息,请问一个单独的问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.