0

0

理解NumPy中np.linalg.norm的数值精度差异及其浮点数比较策略

心靈之曲

心靈之曲

发布时间:2025-10-03 10:28:08

|

337人浏览过

|

来源于php中文网

原创

理解NumPy中np.linalg.norm的数值精度差异及其浮点数比较策略

本文探讨了在NumPy中使用np.linalg.norm计算L2范数平方时,相较于手动展开计算可能引入微小的数值不精确性。这种不精确性源于np.linalg.norm内部的浮点数平方根运算。尽管打印输出可能显示相同结果,但底层数值存在差异,这是因为NumPy的默认打印精度会截断显示。文章提供了详细示例,并建议在比较浮点数时使用np.allclose,同时指出在计算L2范数平方时,直接使用np.sum(np.square(...))可避免此问题。

1. 问题现象:np.linalg.norm与手动计算的差异

在使用numpy进行数值计算时,我们有时会遇到看似相同但实际存在微小差异的结果。以下面的例子为例,我们尝试计算两个数组a和b之间l2范数平方的负一半。

首先,定义两个NumPy数组:

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]])

接下来,我们使用两种方法计算所需的结果:

方法一:使用 np.linalg.norm

这种方法利用 np.linalg.norm 函数来计算L2范数,然后进行平方。

m1 = -np.linalg.norm(a[:, np.newaxis, :] - b[np.newaxis, :, :], axis=-1) ** 2 / 2

方法二:手动展开 L2 范数平方

这种方法直接根据L2范数平方的定义,通过求差、平方和再求和的方式计算。

m2 = -np.sum(np.square(a[:, np.newaxis, :] - b[np.newaxis, :, :]), axis=-1) / 2

当我们打印这两个结果时,它们在视觉上是相同的:

print(m1)
# 输出: [[-116.5 -346.  -73.5]]

print(m2)
# 输出: [[-116.5 -346.  -73.5]]

然而,当我们使用 np.array_equal 进行精确比较时,结果却出乎意料:

print(np.array_equal(m1, m2))
# 输出: False

这表明 m1 和 m2 尽管看起来一样,但底层数值并不完全相等。更有趣的是,如果我们创建一个字面量数组来检查相等性:

sanity_check = np.array([[-116.5, -346. ,  -73.5]])
print(np.array_equal(sanity_check, m1))
# 输出: False

print(np.array_equal(sanity_check, m2))
# 输出: True

这进一步确认了 m1 是“异常”的那个。

2. 数值差异的根源:浮点数精度与中间计算

np.linalg.norm 方法与手动计算方法之间的微小差异,主要源于浮点数运算的本质以及 np.linalg.norm 函数的内部实现。

L2 范数的定义与 np.linalg.norm 的实现

L2 范数(欧几里得范数)的定义是向量各元素平方和的平方根。即 ||x||_2 = sqrt(sum(x_i^2))。 当我们需要计算L2范数的平方时,理论上 ||x||_2^2 = sum(x_i^2)。 np.linalg.norm(..., ord=2) 在内部会执行 sqrt(sum(x_i^2)) 的操作。因此,np.linalg.norm(..., ord=2) ** 2 实际上是 (sqrt(sum(x_i^2))) ** 2。

浮点数运算的精度问题

计算机中,浮点数(如Python中的float,NumPy中的np.float64)的表示是有限精度的。这意味着某些实数无法被精确表示,只能近似。当进行数学运算,尤其是涉及平方根等操作时,这种近似性可能导致微小的误差累积。

考虑一个简单的例子:

print(np.sqrt(8**2 + 13**2)**2)
# 输出: 232.99999999999997

print(8**2 + 13**2)
# 输出: 233

在这个例子中,8**2 + 13**2 结果是精确的整数 233。然而,np.sqrt(233) 会产生一个浮点数近似值,即使这个近似值再被平方,也可能无法完全恢复到原始的整数 233,而是产生一个非常接近但略有偏差的浮点数,例如 232.99999999999997。

黑点工具
黑点工具

在线工具导航网站,免费使用无需注册,快速使用无门槛。

下载

回到我们的 m1 和 m2,m1 的计算路径是: m1 = - (np.sqrt(np.sum(np.square(diff)))) ** 2 / 2 而 m2 的计算路径是: m2 = - np.sum(np.square(diff)) / 2

m1 在中间多了一步 sqrt 操作,正是这一步引入了浮点数精度误差。为了验证这一点,我们可以查看 m1 和 m2 的原始数值:

print(m1.tolist())
# 输出: [[-116.49999999999999, -346.0, -73.5]]

print(m2.tolist())
# 输出: [[-116.5, -346.0, -73.5]]

可以看到,m1 的第一个元素 -116.49999999999999 与 m2 的 -116.5 存在微小的差异。

3. 打印输出的假象:NumPy的显示精度

尽管 m1 和 m2 存在实际的数值差异,但 print() 函数默认情况下却显示它们是相同的。这是因为NumPy的打印选项(由 np.set_printoptions 控制)会根据设定的精度对浮点数进行四舍五入或截断显示。

我们可以通过 np.get_printoptions() 查看当前的打印设置:

print(np.get_printoptions())
# 典型输出示例: {'edgeitems': 3, 'threshold': 1000, 'floatmode': 'maxprec', 'precision': 3, 'suppress': False, 'linewidth': 75, 'nanstr': 'nan', 'infstr': 'inf', 'sign': '-', 'formatter': None, 'legacy': False}

其中,'precision': 3 表示默认显示小数点后3位。由于 m1 和 m2 的差异发生在更低的位数上,因此在默认的显示精度下,这些差异被隐藏了。

如果我们临时提高打印精度,就可以看到实际的差异:

with np.printoptions(precision=17): # 设置更高精度
    print(m1)
    # 输出: [[-116.49999999999998607 -346.00000000000000000  -73.50000000000000000]]
    print(m2)
    # 输出: [[-116.50000000000000000 -346.00000000000000000  -73.50000000000000000]]

通过将 precision 设置为更高的值(例如17),我们能够清晰地看到 m1 和 m2 之间微小的数值差异。

4. 最佳实践与建议

处理浮点数精度问题是数值计算中的常见挑战。以下是一些建议和最佳实践:

4.1 避免直接的浮点数相等性比较

由于浮点数精度问题,直接使用 == 运算符或 np.array_equal() 来比较浮点数通常是不可靠的。即使两个数在数学上应该相等,也可能因为微小的计算误差而导致它们不相等。

4.2 使用容忍度比较:np.allclose()

在比较浮点数时,应使用带有容忍度(tolerance)的比较方法。NumPy 提供了 np.allclose() 函数,它允许指定一个绝对容忍度(atol)和一个相对容忍度(rtol),只有当两个数组的对应元素之差在这些容忍度之内时,才认为它们相等。

# 检查 m1 和 m2 是否在默认容忍度下接近
print(np.allclose(m1, m2))
# 输出: True (通常默认容忍度足以覆盖这种微小差异)

# 可以手动指定容忍度
print(np.allclose(m1, m2, rtol=1e-05, atol=1e-08))
# 输出: True

np.allclose() 是处理浮点数比较的标准方法。

4.3 针对L2范数平方的优化

如果你的目标是计算L2范数的平方,而不是L2范数本身,那么直接使用 np.sum(np.square(...)) 是更优的选择。这种方法避免了中间的 np.sqrt() 操作,从而减少了引入浮点数精度误差的可能性。

# 推荐计算 L2 范数平方的方法
squared_l2_norm = np.sum(np.square(a[:, np.newaxis, :] - b[np.newaxis, :, :]), axis=-1) / 2

这种方法不仅在数值上更精确,而且在某些情况下也可能略微提高计算效率,因为它省去了一次平方根运算。

总结

本文深入探讨了在NumPy中计算L2范数平方时,np.linalg.norm 方法可能引入数值不精确性的问题。核心原因在于 np.linalg.norm 内部的平方根操作会产生浮点数误差,即使随后再进行平方也无法完全消除。同时,NumPy的默认打印精度会掩盖这些微小的差异。为了确保数值比较的准确性,我们应避免直接的浮点数相等性判断,转而使用 np.allclose() 进行容忍度比较。此外,对于L2范数的平方计算,直接使用 np.sum(np.square(...)) 是一种更精确且推荐的实践。理解这些浮点数计算的细微之处,对于编写健壮和高精度的数值代码至关重要。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
python开发工具
python开发工具

php中文网为大家提供各种python开发工具,好的开发工具,可帮助开发者攻克编程学习中的基础障碍,理解每一行源代码在程序执行时在计算机中的过程。php中文网还为大家带来python相关课程以及相关文章等内容,供大家免费下载使用。

778

2023.06.15

python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

686

2023.07.20

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

769

2023.07.25

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

740

2023.07.31

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

1445

2023.08.03

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

571

2023.08.04

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

581

2023.08.04

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

752

2023.08.11

拼多多赚钱的5种方法 拼多多赚钱的5种方法
拼多多赚钱的5种方法 拼多多赚钱的5种方法

在拼多多上赚钱主要可以通过无货源模式一件代发、精细化运营特色店铺、参与官方高流量活动、利用拼团机制社交裂变,以及成为多多进宝推广员这5种方法实现。核心策略在于通过低成本、高效率的供应链管理与营销,利用平台社交电商红利实现盈利。

31

2026.01.26

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.2万人学习

Django 教程
Django 教程

共28课时 | 3.5万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号