0

0

NumPy中np.linalg.norm的数值精度与浮点数打印陷阱解析

心靈之曲

心靈之曲

发布时间:2025-10-03 10:27:18

|

216人浏览过

|

来源于php中文网

原创

NumPy中np.linalg.norm的数值精度与浮点数打印陷阱解析

本文深入探讨了NumPy中np.linalg.norm与手动计算平方范数在数值精度上的差异。尽管print()输出可能显示一致,但np.array_equal可能揭示细微的浮点数不相等。这源于np.linalg.norm内部的开方操作及其后续的平方运算,以及NumPy默认的打印精度设置如何掩盖这些微小差异。文章提供了详细的代码示例和原理分析,并给出处理浮点数比较的建议。

理解数值计算中的微妙差异

在进行科学计算时,尤其是在处理浮点数时,看似等价的操作有时会产生极其微小的数值差异,这些差异在默认的输出显示中可能被隐藏。本节将通过一个具体的numpy示例来揭示这种现象,并深入分析其背后的原因。

假设我们有以下两个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]])

我们希望计算 a 中每个向量与 b 中每个向量之间的欧氏距离的平方,并取负号后除以2。我们尝试两种不同的方法。

方法一:使用 np.linalg.norm 这种方法首先计算向量差的L2范数(即欧氏距离),然后将其平方。

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

方法二:手动计算平方和 这种方法直接计算向量差的平方和,这正是欧氏距离平方的定义。

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

当我们打印 m1 和 m2 的结果时,它们看起来是完全相同的:

m1: [[-116.5 -346.  -73.5]]
m2: [[-116.5 -346.  -73.5]]

然而,当我们使用 np.array_equal 来检查这两个数组是否完全相等时,结果却出人意料:

print(f"np.array_equal(m1, m2): {np.array_equal(m1, m2)}")
# 输出: np.array_equal(m1, m2): False

这表明 m1 和 m2 之间存在差异。更令人困惑的是,如果我们创建一个字面量数组 sanity_check,并与 m1 和 m2 进行比较,会发现:

sanity_check = np.array([[-116.5, -346. ,  -73.5]])
print(f"np.array_equal(sanity_check, m1): {np.array_equal(sanity_check, m1)}")
print(f"np.array_equal(sanity_check, m2): {np.array_equal(sanity_check, m2)}")
# 输出:
# np.array_equal(sanity_check, m1): False
# np.array_equal(sanity_check, m2): True

这表明 m1 是“异常”的一个,它与我们期望的精确值不符,而 m2 却与精确值匹配。

揭示数值差异的真相:浮点数运算的本质

要理解 m1 产生差异的原因,我们需要深入了解浮点数运算的精度问题。np.linalg.norm 函数在计算向量的L2范数时,其内部逻辑是计算 sqrt(sum(v_i^2))。当我们将 np.linalg.norm 的结果再次平方时,实际上执行了 (sqrt(sum(v_i^2)))^2。

在浮点数算术中,sqrt(X)**2 并不总是严格等于 X。由于计算机内部表示浮点数的限制,开方和平方这两个逆操作可能会引入微小的精度损失。

我们可以通过一个简单的例子来验证这一点:

val_squared = 8**2 + 13**2
print(f"8**2 + 13**2: {val_squared}")
print(f"np.sqrt(8**2 + 13**2)**2: {np.sqrt(val_squared)**2}")
# 输出:
# 8**2 + 13**2: 233
# np.sqrt(8**2 + 13**2)**2: 232.99999999999997

可以看到,np.sqrt(233)**2 的结果略小于 233。正是这种微小的精度损失,导致了 m1 与 m2 之间的差异。m2 直接计算了平方和,避免了中间的开方操作,因此保留了更高的精度。

为了直观地看到 m1 和 m2 之间实际的数值差异,我们可以将它们转换为列表,以显示完整的浮点数精度:

Onu
Onu

将脚本转换为内部工具,不需要前端代码。

下载
print(f"m1.tolist(): {m1.tolist()}")
print(f"m2.tolist(): {m2.tolist()}")
# 输出:
# m1.tolist(): [[-116.49999999999999, -346.0, -73.5]]
# m2.tolist(): [[-116.5, -346.0, -73.5]]

现在,m1 在第一个元素上的微小差异清晰可见,而 m2 则精确地保持了期望值。

理解打印输出的“假象”:NumPy的打印选项

为什么 print(m1) 和 print(m2) 的输出看起来完全相同,却在 np.array_equal 中表现出不同呢?这与NumPy的打印选项有关。NumPy通过 np.set_printoptions 函数控制数组的打印格式,包括浮点数的显示精度。

默认情况下,NumPy的打印选项可能设置了较低的显示精度(例如,precision=3),这意味着它只会显示小数点后几位,从而隐藏了那些超出显示精度的微小差异。

我们可以通过 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 参数控制了浮点数的显示精度。当 precision 设置为较小的值时,例如 3,像 232.99999999999997 这样的数字在打印时就会被四舍五入显示为 233.0。

如果我们将打印精度调高,例如设置为 17 位小数,这些隐藏的差异就会显现出来:

np.set_printoptions(precision=17)
print("m1 (高精度):", m1)
print("m2 (高精度):", m2)
# 输出:
# m1 (高精度): [[-116.4999999999999858 -346.0000000000000000  -73.5000000000000000]]
# m2 (高精度): [[-116.5000000000000000 -346.0000000000000000  -73.5000000000000000]]

此时,m1 和 m2 之间的差异在打印输出中也变得可见。

总结与最佳实践

通过上述分析,我们可以得出以下结论和最佳实践:

  1. np.linalg.norm 与精度:当计算欧氏距离的平方(或其他范数的平方)时,如果使用 np.linalg.norm 后再进行平方操作,可能会因为内部的开方和平方过程引入浮点数精度误差。
  2. 避免不必要的开方:对于计算平方欧氏距离等场景,直接使用 np.sum(np.square(diff), axis=-1) 的方式通常比 np.linalg.norm(diff, axis=-1)**2 更具数值稳定性,因为它避免了中间的开方操作。
  3. 理解打印输出的局限性:NumPy的默认打印选项会限制浮点数的显示精度,这可能掩盖实际存在的微小数值差异。在调试数值问题时,应注意调整 np.set_printoptions(precision=...) 或使用 tolist() 等方法查看完整精度。
  4. 浮点数比较的注意事项:由于浮点数的本质,直接使用 == 或 np.array_equal 来比较两个浮点数数组是否相等是危险的,因为即使是理论上应该相等的数值也可能因精度问题而略有不同。推荐使用带容差的比较方法,例如 np.isclose() 或 np.allclose(),它们允许在一定误差范围内判断数值是否“足够接近”。
# 示例:使用 np.allclose 进行浮点数比较
print(f"np.allclose(m1, m2): {np.allclose(m1, m2)}")
# 输出: np.allclose(m1, m2): True (默认容差下认为相等)

# 我们可以通过调整 rtol 和 atol 参数来控制容差
# np.allclose(m1, m2, rtol=1e-05, atol=1e-08)

通过理解这些浮点数计算的细微之处和NumPy的工具特性,我们可以更准确地进行数值分析和编程,避免潜在的精度陷阱。

相关文章

全能打印神器
全能打印神器

全能打印神器是一款非常好用的打印软件,可以在电脑、手机、平板电脑等设备上使用。支持无线打印和云打印,操作非常简单,使用起来也非常方便,有需要的小伙伴快来保存下载体验吧!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

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

豆包大模型
豆包大模型

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

通义千问
通义千问

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

腾讯元宝
腾讯元宝

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

文心一言
文心一言

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

讯飞写作
讯飞写作

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

即梦AI
即梦AI

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

ChatGPT
ChatGPT

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

相关专题

更多
python中print函数的用法
python中print函数的用法

python中print函数的语法是“print(value1, value2, ..., sep=' ', end=' ', file=sys.stdout, flush=False)”。本专题为大家提供print相关的文章、下载、课程内容,供大家免费下载体验。

186

2023.09.27

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

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

27

2026.01.26

edge浏览器怎样设置主页 edge浏览器自定义设置教程
edge浏览器怎样设置主页 edge浏览器自定义设置教程

在Edge浏览器中设置主页,请依次点击右上角“...”图标 > 设置 > 开始、主页和新建标签页。在“Microsoft Edge 启动时”选择“打开以下页面”,点击“添加新页面”并输入网址。若要使用主页按钮,需在“外观”设置中开启“显示主页按钮”并设定网址。

7

2026.01.26

苹果官方查询网站 苹果手机正品激活查询入口
苹果官方查询网站 苹果手机正品激活查询入口

苹果官方查询网站主要通过 checkcoverage.apple.com/cn/zh/ 进行,可用于查询序列号(SN)对应的保修状态、激活日期及技术支持服务。此外,查找丢失设备请使用 iCloud.com/find,购买信息与物流可访问 Apple (中国大陆) 订单状态页面。

28

2026.01.26

npd人格什么意思 npd人格有什么特征
npd人格什么意思 npd人格有什么特征

NPD(Narcissistic Personality Disorder)即自恋型人格障碍,是一种心理健康问题,特点是极度夸大自我重要性、需要过度赞美与关注,同时极度缺乏共情能力,背后常掩藏着低自尊和不安全感,影响人际关系、工作和生活,通常在青少年时期开始显现,需由专业人士诊断。

3

2026.01.26

windows安全中心怎么关闭 windows安全中心怎么执行操作
windows安全中心怎么关闭 windows安全中心怎么执行操作

关闭Windows安全中心(Windows Defender)可通过系统设置暂时关闭,或使用组策略/注册表永久关闭。最简单的方法是:进入设置 > 隐私和安全性 > Windows安全中心 > 病毒和威胁防护 > 管理设置,将实时保护等选项关闭。

5

2026.01.26

2026年春运抢票攻略大全 春运抢票攻略教你三招手【技巧】
2026年春运抢票攻略大全 春运抢票攻略教你三招手【技巧】

铁路12306提供起售时间查询、起售提醒、购票预填、候补购票及误购限时免费退票五项服务,并强调官方渠道唯一性与信息安全。

32

2026.01.26

个人所得税税率表2026 个人所得税率最新税率表
个人所得税税率表2026 个人所得税率最新税率表

以工资薪金所得为例,应纳税额 = 应纳税所得额 × 税率 - 速算扣除数。应纳税所得额 = 月度收入 - 5000 元 - 专项扣除 - 专项附加扣除 - 依法确定的其他扣除。假设某员工月工资 10000 元,专项扣除 1000 元,专项附加扣除 2000 元,当月应纳税所得额为 10000 - 5000 - 1000 - 2000 = 2000 元,对应税率为 3%,速算扣除数为 0,则当月应纳税额为 2000×3% = 60 元。

11

2026.01.26

oppo云服务官网登录入口 oppo云服务登录手机版
oppo云服务官网登录入口 oppo云服务登录手机版

oppo云服务https://cloud.oppo.com/可以在云端安全存储您的照片、视频、联系人、便签等重要数据。当您的手机数据意外丢失或者需要更换手机时,可以随时将这些存储在云端的数据快速恢复到手机中。

39

2026.01.26

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
SciPy 教程
SciPy 教程

共10课时 | 1.3万人学习

R 教程
R 教程

共45课时 | 5.6万人学习

SQL 教程
SQL 教程

共61课时 | 3.6万人学习

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

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