float32矩阵乘法的边界误差

计算科学 数字 稳定
2021-11-30 05:11:04

一些数值调试使我得到了下面的最小示例。我观察到单个元素的相对误差为 0.75。

有没有办法在不诉诸更高精度算术的情况下估计/限制这个错误?

import numpy as np
x = np.array([[11041, 13359, 15023, 18177], [13359, 16165, 18177, 21995], [15023, 18177, 20453, 24747], [18177, 21995, 24747, 29945]])
y = np.array([[29945, -24747, -21995, 18177], [-24747, 20453, 18177, -15023], [-21995, 18177, 16165, -13359], [18177, -15023, -13359, 11041]])

print(x@y)          # high precision

#[[16  0  0  0]
# [ 0 16  0  0]
# [ 0  0 16  0]
# [ 0  0  0 16]]

x0 = x.astype(np.float32)
y0 = y.astype(np.float32)
print(x0@y0)        # low precision

#[[28.  0. -4.  0.]
# [ 0. 28.  0. -4.]
# [20.  0. 20.  0.]
# [ 0. 20.  0. 20.]]

这个例子来自使用精确算术计算X1,并检查XX1在 float32 中

X=AABB
A=(5678)  B=(9101112)

1个回答

估计误差:是的,这是舍入误差分析的标准材料。例如,参见 Higham 的数值算法的准确性和稳定性中的 (3.13) :如果C=ABC^是它的计算版本,那么

|CC^|γn|A||B|,
其中绝对值是按分量取的,并且γn=nu1nu=nu+O(u2), 和u机器精度(大约6e-8在单精度)和n矩阵大小。

本质上,舍入误差取决于绝对值矩阵的乘积,或计算标量乘积时遇到的中间结果的大小,因为您必须将它们存储在单精度变量中。在您的情况下,这些中间值大约为105105=1010,所以你不能指望比你得到的错误更小。请注意,您的输入值在其最后一个(单精度)有效数字中的扰动会以相同的幅度扰动结果,因此您无法做得更好。当你写完x0 = x.astype(np.float32)并忘记这些是你已经丢失的精确整数的那一刻。

解决方法:更高精度或整数算术,或者理论上因为您使用整数计算,您可以执行计算模数几个不同的互质值并使用中国剩余定理来推断最终结果 --- 但如果您的计算在这个规模可能只是不值得努力。