numpy中交叉积的数值精度

时间:2016-06-03 00:14:29

标签: python numpy precision cross-product

我正在体验我认为在numpy中使用具有较大值的交叉产品的奇怪行为。

例如,以下似乎是正确的:

r = 1e15
a = array([1, 2, 3]) * r;
b = array([-1, 2, 1]) * r;

c = cross(a / norm(a), b / norm(b));

print(dot(c, a))  # outputs 0.0

但如果我们将指数提高1,我们得到:

r = 1e16
a = array([1, 2, 3]) * r;
b = array([-1, 2, 1]) * r;

c = cross(a / norm(a), b / norm(b));

print(dot(c, a))  # outputs 2.0

对于较大的指数值,数字变得更加离奇。有谁知道这里发生了什么?谢谢!

1 个答案:

答案 0 :(得分:2)

您看到了圆整错误。默认情况下,array()会返回dtype=float64的对象。当你使r变得越来越大时,你的尾数空间就会用完,无法准确地表示数组产品。这是一种测试方法:

def testcross(r, dt):
    a = array([1, 2, 3], dtype=dt)*r
    b = array([-1, 2, 1], dtype=dt)*r
    c = cross(a/norm(a), b/norm(b))
    return dot(c, a)

for rr in logspace(4, 15, 10):
    print "%10.2f %10.2f %g" % (testcross(rr, float32), testcross(rr, float64)

结果:

     -0.00       0.00 10000
      0.00      -0.00 166810
      0.00       0.00 2.78256e+06
     -4.00       0.00 4.64159e+07
    -64.00       0.00 7.74264e+08
   1024.00       0.00 1.29155e+10
      0.00       0.00 2.15443e+11
-524288.00       0.00 3.59381e+12
      0.00      -0.02 5.99484e+13
-134217728.00       0.00 1e+15

请注意,即使float64 r=5.99484e13,事情也不“完美”。这表明,在到达r=1e15之前,即使float64,精度也开始下降。正如预期的那样,对于不太精确的float32,情况会更糟。

跟进OP的建议:32位和64位浮点表示的尾数字段分别为24和53位(包括隐含位)。以log10([2**24, 2**53])为例,我们发现这分别对应约7和16个数量级。这与最初提到的r=4.6e7float32 r=1e16左右的列表错误相对应。当点积导致基础矩阵计算减去大数时,会发生舍入,并且差异不能表示为一个或另一个大数的尾数。