线性插值计算是否会因舍入误差导致结果超出[v0, v1]区间
结论
断言不会始终成立,完全有可能因为浮点数舍入误差触发失败。
原因说明
浮点数的乘法、加法运算本身就不是精确的,每一步运算都会按照当前精度规则做舍入,这个插值公式拆分了4次浮点运算(1次减法算1.0 - r、2次乘法、1次加法),多步的舍入误差叠加之后,最终结果完全可能略超出[min(v0, v1), max(v0, v1)]的区间范围。
可复现的失败示例
你可以在C/C++环境下运行这段代码复现断言失败的情况:
#include <assert.h> #include <math.h> #include <stdio.h> int main() { double v0 = 1.0; // 取比1.0小的最大double值 double v1 = nextafter(1.0, 0.0); double r = 1.0 - 0x1.0p-53; double v = v0 * r + v1 * (1.0 - r); printf("v0 = %.17g\nv1 = %.17g\n计算得到的v = %.17g\n", v0, v1, v); // 这里断言会触发,因为计算得到的v会略小于v1 if (v0 <= v1) assert(v0 <= v && v <= v1); else assert(v1 <= v && v <= v0); return 0; }
补充说明
哪怕换成另一种常见的线性插值写法v = v1 + r * (v0 - v1),也同样存在舍入误差导致出界的可能,如果业务逻辑不允许插值结果出界,需要在计算完成后手动把结果钳位到[min(v0, v1), max(v0, v1)]区间内。
内容的提问来源于stack exchange,提问作者user2052436
相关产品推荐
相关产品推荐

