为何使用np.linalg.norm会产生数值不等,手动实现却无此问题?
np.linalg.norm与平方求和的数值差异问题分析
前提代码
import numpy as np a = np.array([[ 0, 1, 10, 2, 5]]) b = np.array([[ 0, 1, 18, 15, 5], [13, 9, 23, 3, 22], [ 2, 10, 17, 4, 8]])
两种计算方法
方法1(使用np.linalg.norm)
m1 = -np.linalg.norm(a[:, np.newaxis, :] - b[np.newaxis, :, :], axis=-1) ** 2 / 2
方法2(直接平方求和)
m2 = -np.sum(np.square(a[:, np.newaxis, :] - b[np.newaxis, :, :]), axis=-1) / 2
测试现象
- 打印输出外观一致:
array([[-116.5, -346. , -73.5]])
- 相等性检查结果:
>>> np.array_equal(m1, m2) False >>> sanity_check = np.array([[-116.5, -346. , -73.5]]) >>> np.array_equal(sanity_check, m1) False >>> np.array_equal(sanity_check, m2) True
原因解释
1. np.linalg.norm的计算引入精度误差
np.linalg.norm计算L2范数时,会先对元素平方求和,再开平方根,之后我们又对结果做了平方操作。这个开根号再平方的额外步骤会引入浮点数精度损失:浮点数无法精确表示所有实数,开根号过程中产生的微小误差会在平方后被保留,导致最终结果和直接平方求和的m2存在微小差异。
而方法2直接对差值平方后求和,没有开根号的中间步骤,完全基于整数运算(差值的平方都是整数,求和后也是整数),除以2后得到的是精确的浮点数(如-116.5是精确可表示的),所以能和字面量sanity_check完全匹配。
2. 打印格式化掩盖了数值差异
numpy在打印数组时,会默认对浮点数进行格式化输出(通常显示1-2位小数),把微小的精度差异隐藏了。但实际上m1存储的是带有微小误差的浮点数,比如可能是-116.50000000000001或者-116.49999999999999,这些值在打印时会被四舍五入显示为-116.5,但和精确值的严格相等检查会失败。
内容的提问来源于stack exchange,提问作者Flair
相关产品推荐
相关产品推荐

