You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Numpy在该计算场景中出现舍入问题?

浮点数精度问题详解:你的代码误差根源解析

先看你的代码:

import numpy as np

def calc_negation(negations):
    takens = 1. - negations
    return 1. - np.prod(takens, axis=1, keepdims=True)

result = calc_negation(np.array([[.1, .1], [.5, .5]]))
expected =  np.array([[.19], [.75]])

print(result)
print(result == expected)  # show the failed equality.

assert result.shape == (2, 1)
assert result.shape == expected.shape
assert result.dtype == expected.dtype

assert expected[0, 0] == .19  # why is this okay!?!
assert expected[1, 0] == .75
assert np.allclose(result, expected)  # why is numpy rounding 1 - (.9 * .9)? 
assert np.array_equal(result, expected)  # FAILS!

核心原因:二进制浮点数的固有局限

十进制里的0.1、0.9、0.19这类数,在二进制中是无限循环小数,无法被标准浮点数(Python的float、numpy的float64)精确存储,只能以近似值形式存在。不同计算路径会产生不同的近似结果,这就是所有问题的根源。

1. 为什么result[0,0] != 0.19,但expected[0,0] == .19?

  • 当你直接写.19或用np.array([[.19]])创建数组时,这个值是直接将十进制0.19转换为二进制浮点数的近似值,其精确展开为0.19000000000000000333(保留20位小数)。
  • result[0,0]是计算产物:
    • 0.9的二进制近似值是0.90000000000000002220,两者相乘得到0.81000000000000005551;
    • 1减去这个值得到0.18999999999999994449,和直接写的.19的二进制表示完全不同,所以精确相等判断失败。
  • 而expected[0,0] == .19成立,是因为两者是同一个浮点数近似值,二进制位完全一致。

2. 为什么误差不是你熟悉的“微小正误差”?

浮点数的近似误差方向由转换/计算路径决定:

  • 直接转换十进制0.19时,二进制近似值略大于真实值;
  • 通过1 - 0.9*0.9计算时,0.9的近似值略大于真实值,相乘后结果略大于0.81,1减去它就得到略小于0.19的结果。
    误差方向相反,自然就不是你习惯的“0.19000000000004”这类正误差。

3. 为什么np.allclose通过但np.array_equal失败?

  • np.array_equal是精确匹配判断,要求两个数组的每个元素二进制表示完全一致,所以会失败;
  • np.allclose是近似匹配判断,默认检查元素差是否在浮点数合理误差范围内(相对误差1e-05,绝对误差1e-08),你的两个结果的差远小于这个阈值,所以通过。

解决方案

如果需要避免这类精度问题,可以:

  • 使用Python标准库的decimal模块,支持高精度十进制运算;
  • 对numpy数组,优先用np.allclose替代精确相等判断来比较浮点数;
  • 部分平台可使用np.float128类型,提供更高精度的浮点数存储。

内容的提问来源于stack exchange,提问作者philosofool

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 00:05:17