Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $YECBGYFECGEAFWHA as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2

Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $BBWFDDBHHYHDXXAB as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2
理解NumPy中np.linalg.norm的数值精度差异及其浮点数比较策略_创想鸟

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

理解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 npa = 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))# 输出: Falseprint(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.99999999999997print(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(…)) 是一种更精确且推荐的实践。理解这些浮点数计算的细微之处,对于编写健壮和高精度的数值代码至关重要。

以上就是理解NumPy中np.linalg.norm的数值精度差异及其浮点数比较策略的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1375243.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
Python脚本冻结:理解并修正无限循环与缩进错误
上一篇 2025年12月14日 14:50:34
NumPy中np.linalg.norm的数值精度与浮点数打印陷阱解析
下一篇 2025年12月14日 14:50:42

相关推荐

  • 数据库分库分表(Sharding)策略

    在现代应用程序中,随着数据量的增长,单一数据库的性能和容量往往难以满足需求。这时,数据库分库分表(Sharding)策略就成了一个关键的解决方案。那么,如何设计和实现一个有效的分库分表策略呢?让我们深入探讨一下。 在我的职业生涯中,我曾多次参与大型项目的数据库优化,其中分库分表是常见的挑战之一。我记…

    2026年9月21日
    000
  • VSCode的代码折叠功能好用吗?

    VSCode代码折叠功能支持多种方式:点击箭头、快捷键、命令面板及按区域类型折叠;可自定义基于缩进的折叠、默认层级和提示装饰器;集成语言服务后能智能识别JSX、Vue组件等结构,提升大型文件编辑效率。 VSCode 的代码折叠功能非常实用,尤其在处理大型文件或复杂结构时能显著提升阅读和编辑效率。 支…

    2026年9月21日
    100
  • win10无法创建新的分区提示空间不足怎么办 _Win10 无法创建分区空间不足解决方法

    首先检查磁盘是否存在未分配空间,若无则通过压缩卷释放空间;使用磁盘管理或第三方工具如EaseUS创建新分区;必要时清理磁盘或转换MBR为GPT格式以突破分区限制。 如果您在使用Windows 10系统时尝试创建新的磁盘分区,但系统提示“无法创建新分区”或“空间不足”,这通常是因为当前磁盘未分配的空间…

    2026年9月21日
    100
  • Guava Multimap:高效获取并打印指定键的所有关联值

    guava multimap是处理一键多值映射关系的强大工具。要获取特定键的所有关联值,应直接使用其提供的`multimap#get(k)`方法。该方法会返回一个包含所有匹配值的`collection`,即使键不存在,也会返回一个空集合而非`null`,从而简化了值检索和空值处理逻辑,是比手动迭代键…

    2026年9月21日
    000
  • 控制台命令(Console Command)开发

    控制台命令是程序员日常工作中不可或缺的工具,它提高了开发效率并帮助理解和控制程序运行。1) 通过简单的文本输入,完成复杂任务,如文件管理和系统监控。2) 控制台命令可用于快速调试、测试代码和自动化重复工作。3) 开发控制台命令时需注意安全性和兼容性问题。4) 控制台命令可实现有趣功能,如监控服务器资…

    2026年9月21日
    100
  • Windows10无法启用或关闭Windows功能怎么办_Windows10Windows功能无法启用关闭修复方法

    首先启动Windows Modules Installer服务,然后通过注册表编辑器设置RegistrySizeLimit为FFFFFFFF以释放内存限制,接着使用SFC和DISM命令修复系统文件,最后运行系统自带的疑难解答工具并重启电脑,可解决Windows功能窗口加载缓慢或空白的问题。 如果您尝…

    2026年9月21日
    000
  • edge浏览器怎么设置网页的最小字号_edge浏览器字体显示大小调整技巧

    1、调整Edge浏览器字体大小可改善阅读体验,进入设置→外观→字体大小,选择“大”或“超大”;2、通过edge://settings/fonts设置最小字体大小,防止文字过小;3、使用右上角缩放功能或Ctrl+滚轮临时放大页面;4、在辅助功能中开启自定义字体并选择易读字体如“微软雅黑”,提升可读性。…

    2026年9月21日
    300
  • Windows10提示“远程过程调用失败”怎么办_Windows10RPC远程过程调用失败修复方法

    首先检查并启动RPC相关服务,确保Remote Procedure Call (RPC)和DCOM Server Process Launcher设为自动并运行;其次临时关闭防火墙和杀毒软件以排除网络通信阻断;接着使用sfc /scannow和DISM命令修复系统文件;最后确认网络适配器中TCP/I…

    2026年9月21日
    000
  • 自定义协议与主流框架(如ThinkPHP)结合

    在thinkphp中实现自定义协议可以通过中间件机制。具体步骤包括:1. 创建中间件类customprotocolmiddleware,解析和验证请求的json格式和字段。2. 在应用配置文件中添加该中间件,使所有请求经过处理。通过这种方式,可以满足特定业务需求并提升应用的灵活性和可扩展性。 在开发…

    2026年9月21日
    000
  • 如何基于Swoole开发自定义框架?

    基于swoole开发自定义框架可以通过以下步骤实现:1. 创建核心app类,初始化swoole服务器并定义回调函数;2. 实现路由功能,使用router类处理请求分发;3. 添加中间件支持,使用middleware类处理请求;4. 集成异步数据库操作,使用swoole的mysql协程客户端;5. 实…

    2026年9月21日
    100
  • Windows11的Hyper-V虚拟机无法启动怎么解决_Windows11Hyper-V虚拟机无法启动修复方法

    首先检查BIOS中是否启用虚拟化技术,再确认Hyper-V服务运行状态,接着修复虚拟硬盘权限,尝试关闭内存完整性,检查虚拟机引导记录,最后可重装Hyper-V功能解决启动失败问题。 如果您尝试在Windows 11系统中启动Hyper-V虚拟机时遇到失败,可能是由于服务配置、权限问题或硬件兼容性导致…

    2026年9月21日
    000
  • 万人同时在线抽奖活动架构

    万人同时在线抽奖活动的系统架构应采用微服务架构、分布式数据库、redis缓存、区块链存储结果,并使用负载均衡和异步处理技术。具体包括:1.采用微服务架构和分布式数据库(如tidb)保证系统稳定性和可扩展性;2.使用redis处理抽奖逻辑,确保高效和随机性;3.将结果存入区块链,保证透明度和可验证性;…

    2026年9月21日
    000
  • Linux文件和目录管理常见命令

    Linux文件和目录管理依赖于ls、cd、mkdir、rm、cp、mv等核心命令,用于浏览、创建、删除、复制和移动文件与目录;通过find、du、grep等命令可查找文件、定位大文件并清理磁盘空间;使用rename、mmv或脚本可实现批量重命名;为安全起见,应谨慎使用rm命令,推荐结合-i选项或使用…

    2026年9月21日
    000
  • 大数据量下的批量导入/导出优化

    在大数据环境下优化批量导入/导出的方法包括:1. 使用批处理技术分批导入/导出数据,减少系统资源压力;2. 采用数据流技术如apache kafka进行实时处理,降低内存占用;3. 利用并行处理技术分配任务到多个处理器或节点,提高处理速度;4. 通过性能监控和调优识别并解决瓶颈点,以提升整体效率。 …

    2026年9月21日
    200
  • windows怎么禁用sticky keys粘滞键_Windows粘滞键关闭方法

    粘滞键被误触后可通过快捷键、控制面板、注册表或组策略关闭。首先连续按Shift键五次,在弹出窗口中选择关闭;其次通过控制面板的“轻松使用”设置取消勾选启用粘滞键;若需彻底禁用,可修改注册表中StickyKeys项的Flags值为506;专业版用户还可通过组策略编辑器将“启用粘滞键”设为已禁用,防止再…

    2026年9月21日
    1000
  • edge浏览器如何安装Chrome网上应用店的扩展_edge浏览器安装Chrome扩展方法

    答案:可通过四种方法在Edge浏览器中安装Chrome扩展。1、直接从Chrome网上应用店添加扩展,Edge会自动识别并安装;2、手动下载CRX或ZIP文件,通过开启开发者模式加载已解压的扩展程序;3、从Crx4Chrome等第三方平台下载兼容扩展并按手动方式安装;4、对扩展的manifest.j…

    2026年9月21日
    000
  • 自定义组件(Component)的开发方法

    开发自定义组件的步骤包括:1. 使用html和css定义组件结构和样式;2. 用javascript实现动态效果和状态管理;3. 确保跨浏览器和设备兼容性;4. 采用模块化设计和外部状态管理工具;5. 进行性能优化和测试驱动开发。通过这些步骤,可以创建出优雅且高效的自定义组件,提升用户体验。 在开发…

    2026年9月21日
    000
  • CODE函数使用技巧

    CODE函数使用技巧CODE函数使用技巧CODE函数使用技巧CODE函数使用技巧

    计算机中的每个字符都有其唯一的编码。例如,大写字母a到z分别对应编码65至90,小写字母a到z则对应97至122,其中字母a的ascii码为65。code函数的作用是提取指定文本的第一个字符,并返回其对应的ascii数值编码,便于实现字符与数字之间的转换,在数据处理和编程中具有广泛应用。 1、 参考…

    2026年9月21日 • 用户投稿
    000
  • mysql如何排查磁盘IO瓶颈

    首先检查系统级磁盘IO,使用iostat、iotop等工具分析磁盘利用率和进程IO行为;再通过MySQL慢查询日志、sys.schema视图及SHOW ENGINE INNODB STATUS排查高IO消耗的SQL与内部等待事件;接着评估innodb_buffer_pool_size、innodb_…

    2026年9月21日
    000
  • win11右下角操作中心图标点击无反应怎么办_Win11操作中心图标无反应修复方法

    1、重启Windows资源管理器可解决因进程异常导致的操作中心无响应问题;2、运行DISM和SFC命令修复系统文件损坏;3、通过Windows更新安装最新补丁;4、在组策略中确保“删除通知和操作中心”未被启用;5、使用系统恢复选项重新安装系统组件以排除配置冲突,适用于专业版或企业版用户。 如果您尝试…

    2026年9月21日
    200

发表回复

登录后才能评论
关注微信