我有一个NumPy数组,其中f**2中的条目与f[i]**2中的条目不同,但只针对某些特定值.

import numpy as np
np.set_printoptions(precision = 16)

f = np.array([ -40709.6555510835, -40708.6555510835, -33467.081758611654, -27653.379955714125])

f2 = f**2
# f2 = np.power(f,2)

print("outside loop", np.abs(f[1]**2 - f2[1]), np.abs(1.0 - f2[1] / f[1]**2), f.dtype, f[1].dtype, f2.dtype, f2[1].dtype)

for i, val in enumerate(f):        
    print("inside loop", i, np.abs(val**2 - f2[i]), np.abs(1.0 - f2[i] / val**2), val.dtype, f2.dtype, f2[i].dtype)

生成输出:

outside loop 2.384185791015625e-07 2.220446049250313e-16 float64 float64 float64 float64
inside loop 0 0.0 0.0 float64 float64 float64
inside loop 1 2.384185791015625e-07 2.220446049250313e-16 float64 float64 float64
inside loop 2 0.0 0.0 float64 float64 float64
inside loop 3 0.0 0.0 float64 float64 float64

我确实注意到,这是一个在epsilon量级上的相对错误.

f2的定义中使用np.power而不是**时,这个问题就不存在了. 即便如此,为什么f[i]**2不等于第i个值f**2(即使只针对f中的某些值).

我使用的是python3.10.6和最新的NumPy 1.26.4.

编辑:

根本问题体现在:

import numpy as np
f = np.array([-40708.6555510835])
print((f[0])**2 - (f**2)[0])

它显示的值为

-2.384185791015625e-07

我想知道为什么那个特定的数字会有这个特定的问题.如果您想要确认,或者想try f的不同值,请查看这个demo.

推荐答案

结果不同,因为f**2呼叫numpy.square,而f[0]**2numpy.power(f, 2)呼叫numpy.power.


numpy.ndarray.__pow__用C.It looks like this写成:

static PyObject *
array_power(PyObject *a1, PyObject *o2, PyObject *modulo)
{
    PyObject *value = NULL;

    if (modulo != Py_None) {
        /* modular exponentiation is not implemented (gh-8804) */
        Py_INCREF(Py_NotImplemented);
        return Py_NotImplemented;
    }

    BINOP_GIVE_UP_IF_NEEDED(a1, o2, nb_power, array_power);
    if (fast_scalar_power(a1, o2, 0, &value) != 0) {
        value = PyArray_GenericBinaryFunction(a1, o2, n_ops.power);
    }
    return value;
}

value = PyArray_GenericBinaryFunction(a1, o2, n_ops.power);是对numpy.power ufunc对象的一个Python函数调用,但首先,它try 一个fast_scalar_power函数.此函数try 优化常用标量幂的求幂,如2.

对于f**2运算,fast_scalar_power检测2的指数,delegates运算到numpy.square:

else if (exponent ==  2.0) {
    fastop = n_ops.square;
}

对于numpy.power(f, 2),这当然是对numpy.power的直接呼叫.numpy.power不会经过fast_scalar_power,也不会对2的指数进行任何特殊处理.(不过,根据它遇到的底层POWER实现,该实现可能仍然会对2进行特殊处理.)

对于标量,我相信numpy.float64.__pow__ actually just calls array_power:

static PyObject *
gentype_power(PyObject *m1, PyObject *m2, PyObject *modulo)
{
    if (modulo != Py_None) {
        /* modular exponentiation is not implemented (gh-8804) */
        Py_INCREF(Py_NotImplemented);
        return Py_NotImplemented;
    }

    BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_power, gentype_power);
    return PyArray_Type.tp_as_number->nb_power(m1, m2, Py_None);
}

所以它达到了fast_scalar_power,但fast_scalar_powerone of the first checks

if (PyArray_Check(o1) &&

numpy.float64的实例不会通过PyArray_Check,这将判断类型正好为numpy.ndarray的对象.因此,标量通过一般的numpy.power代码路径.

Python相关问答推荐

Locust请求中的Python和参数

Pandas 在最近的日期合并,考虑到破产

_repr_html_实现自定义__getattr_时未显示

scikit-learn导入无法导入名称METRIC_MAPPING64'

按顺序合并2个词典列表

如何列举Pandigital Prime Set

为什么sys.exit()不能与subproccess.run()或subprocess.call()一起使用

当独立的网络调用不应该互相阻塞时,'

运输问题分支定界法&

NumPy中条件嵌套for循环的向量化

在含噪声的3D点网格中识别4连通点模式

如何在两列上groupBy,并使用pyspark计算每个分组列的平均总价值

具有相同图例 colored颜色 和标签的堆叠子图

在Google Drive中获取特定文件夹内的FolderID和文件夹名称

Pandas 数据帧中的枚举,不能在枚举列上执行GROUP BY吗?

如何使用大量常量优化代码?

Polars表达式无法访问中间列创建表达式

如果服务器设置为不侦听创建,则QWebSocket客户端不连接到QWebSocketServer;如果服务器稍后开始侦听,则不连接

如果列包含空值,则PANAS查询不起作用

如何在networkx图中提取和绘制直接邻居(以及邻居的邻居)?