引起数学模型数值问题的原因有很多种,例如前面的文章《约束系数的四舍五入引起的模型数值问题》提到,对约束系数的四舍五入,会损失一定的系数精度信息,导致约束面发生一定的偏移,这种偏移无论多么轻微,都有可能导致问题求解结果出现较大差异,但这种情况是我们能够通过避免四舍五入而减少的,还有一种情况也是由于精度缺失引起的,但这种情况在很多时候一不注意很容易忽视。
我们先来看几个例子:
if 1 == 1+1e-16:
print("Equality")
else:
print("Inequality")
输出:
Equality
惊奇的是,尽管等式两边不相等,但python在判断时结果出错,这是极小值存在的误差,那我们再来看一个例子:
if 1e16 == 1+1e16:
print("Equality")
else:
print("Inequality")
输出仍然为:
Equality
说明了这种精度的损失并不只出现在极小值身上,也出现在极大值身上,关键是在于当极小值和极大值同时出现时,相对小的数值就可能在这个过程中被忽略,从而造成等式关系的误判,而仅仅是等式关系的误判,会衍生出大量复杂的问题,例如:
if (1+1e-16)+1e-16 == 1+(1e-16+1e-16):
print("Equality")
else:
print("Inequality")
输出结果为:
Inequality
类似的,既然忽视数值精度会导致原本不相等的两个关系式相等,衍生地也会导致原本相等的两个关系式不相等。上面的例子由于前面的括号先计算,损失了 1 e ? 16 1e-16 1e?16,再加上 1 e ? 16 1e-16 1e?16,此时相当于还是等于 1,而后面的公式相当于 1 + 2 ? 1 e ? 16 1+2*1e-16 1+2?1e?16,此时后者达到了存储精度,并不会损失这部分信息, 1 + 2 ? 1 e ? 16 > 1 1+2*1e-16\gt 1 1+2?1e?16>1。
当要表征较大值或极小值时,计算机需要用更多位数的信息来记录精度,但这在一定程度上会降低运算效率,因此,很多时候在不声明精度范围时,python或者求解器会有一个默认的极小值范围,例如python默认在逻辑运算式当中, 1 e ? 16 1e-16 1e?16是一个边界量会被忽视,而 1 e ? 15 1e-15 1e?15不被忽视。因此,需要考虑到由于存储精度引起的模型数值问题,常见的思路是尽量避免一个模型当中同时出现两个量级相差悬殊的数值。