Apple libm的sin函数在小输入时为何执行冗余乘法后返回x?
Apple libm sin函数小输入场景的冗余浮点乘法解析
问题背景
当输入x足够小时,sin(x)的最接近浮点数就是x,但Apple libm的sin函数并未直接返回x,而是执行了一次无实际结果使用的浮点乘法,关键代码如下:
/* Make t0 volatile to force compiler to fetch it at run-time rather than optimizing away the multiplication. */ static volatile const double t0 = 1/3.; /* Get t0 once. If we wrote "t0*t0", the compiler would load it twice, since it is volatile. */ const double t1 = t0; /* Perform a multiplication and pass it into an assembly construct to prevent the compiler from knowing we do not use the result and optimizing away the multiplication. */ __asm__("" : : "X" (t1*t1)); // Return the floating-point number nearest sine(x), which is x. return x;
设计意图
这段冗余代码的核心目的是保证函数执行时间的一致性,避免分支带来的性能抖动:
- 作为基础数学库,libm的调用场景常包含对延迟敏感的应用(如实时系统、高频数值计算),这类场景要求函数执行时间尽可能稳定,不能因输入不同出现大幅波动。如果小输入场景直接返回
x,其执行时间会远短于需要泰勒展开、查表等复杂计算的场景,这种时间差可能引发时序问题。 - 执行一次浮点乘法的开销极低,能让小输入场景的执行时间和其他场景的基础计算开销对齐,抹平分支导致的时间差异。
同时,代码中的特殊处理是为了防止编译器优化掉这个“无用”操作:
static volatile const double t0确保t0会在运行时被加载,而非被编译器提前做常量折叠优化。__asm__("" : : "X" (t1*t1))通过空汇编语句向编译器传递“该乘法结果被使用”的信号,阻止编译器将整个乘法操作删除。
内容的提问来源于stack exchange,提问作者Matthew Towers
相关产品推荐
相关产品推荐

