我浏览了一个代码库,发现了以下模板函数:
template <class T, class T2>
T mix(const T &a, const T &b, const T2 &interp) {
static constexpr T2 one = ((T2)1);
return (a * (one - interp)) + (b * interp);
}
以下评论
// You'd think instead of doing the a*(1-t) + b*t, it'd be faster
// and one less multiply to do a + (b-a)*t, right? Bad! Increases floating
// point exception occurances. Same as LERP
有人能强调为什么这是真的吗?
正如Paul R在评论中所说,这些评论可能指的是非正规(我通常认为它们被描述为亚正规,所以会使用这个术语)数字,它们填补了浮点运算中零附近的下溢空白。
如果a
和b
的值足够接近,则a-b
将产生亚正常值。当这些值完全在硬件中处理时,性能通常会受到影响。在硬件中有一些技术可以缓解这种情况,但在一些现代处理器中,涉及子规范的指令可能比作用于正常值的相同指令花费100多倍的时间。如果这些值完全在软件中处理(例如,硬件指令不直接处理它们,并且出现浮点异常,必须在软件中捕获并进行排序),那么性能几乎总是会下降。
根据应用程序的类型,所产生的问题可能从无关紧要(例如,对于不经常遇到子规范的长数值计算,额外的几毫秒)到主要问题(例如,在安全相关系统中引入潜在的定时侧信道)不等。
问题中给出的解决方案确实依赖于interp
本身既不是亚正规,也不是太接近1.0
。