DEBUG.WIKI
阿里云;从建站到云上业务;云服务器 · 数据库 · 对象存储;查看产品 →
搬瓦工;先看线路,再选 VPS;CN2 GIA · 对应线路套餐;查看线路 →
野草云;香港 200Mbps 峰值;不限月流量 · BGP VPS;查看套餐 →

Windows NumPy 求巨大复数平方根,虚部为何少了一半

NumPy 2.5.4 的部分 Windows 复数 sqrt 备用实现恢复缩放时只处理实部。对巨大有限输入局部缩放,并保留平台与特殊值边界。

Windows 上对一个接近 float64 上限的纯虚数求平方根,实部与虚部本应绝对值相等,结果虚部却只有实部的一半。若是 NumPy 2.5.4 的相关 Windows 构建,应检查复数平方根的缩放回填,而不是先降低计算精度。

明确的触发值接近 complex(0, np.finfo(np.float64).max)。NumPy 的兼容实现为了避免中间计算溢出,会先把复数的两个分量缩小为四分之一,计算平方根后再还原。2.5.4 的该备用分支只把实部乘回二,虚部没有同步恢复。

这段代码位于缺少相应 C 数学函数时采用的实现。平台使用系统 C99 复数函数时,未必经过这里,不能把同一结果扩大到所有 Linux、macOS 或所有 Windows 安装方式。

已知是巨大有限输入时,可在调用外完成缩放

若应用确实需要处理这一级数量的有限 complex128 值,可以让库收到较小的数,再统一恢复两个结果分量。下面只展示高量级分支,普通数值仍直接求根:

import numpy as np

value = np.complex128(complex(0.0, np.finfo(np.float64).max))
limit = np.finfo(np.float64).max / (1.0 + np.sqrt(2.0))

if not (np.isfinite(value.real) and np.isfinite(value.imag)):
    raise ValueError("this path requires finite components")
if max(abs(value.real), abs(value.imag)) >= limit:
    root = np.sqrt(value / 4.0) * 2.0
else:
    root = np.sqrt(value)

这里利用正实数缩放下平方根的关系,避免库内再次进入巨大输入分支。它不是对已经算错的结果整体乘二:原结果的实部已经恢复,事后把两个分量都乘二,会让实部也变错。

不要不分范围地对所有输入都先除四。很小的分量可能因此下溢;NaN、无穷和带符号零也有独立的复数分支语义,示例没有替这些输入定义新结果。实际使用复数数组时,应在保留 dtype、形状和有限值掩码的前提下,仅对确认需要缩放的位置处理。

验证要避开另一次溢出

纯虚数的平方根满足实部与虚部绝对值相等,虚部符号随输入变化。检查这个关系,比直接计算 root * root 后要求与最大浮点数逐位相等更合适;后者本身又可能在复数乘法的中间步骤溢出。

保留平台、包来源、输入 dtype 与量级,分别核对正负巨大虚部、普通数值及阈值附近结果。这与Windows 的 finfo 缓存导致 linalg 拒绝类型不是同一故障:本题是 sqrt 备用实现恢复比例错误,不靠调整导入顺序解决。

截至 2026 年 10 月 26 日,不能将主线修补建议当成 2.5.4 已有的修复。更新依赖后,应在原 Windows 构建与实际计算入口重新检查,再决定是否撤去局部缩放。