np.int64 在数学运算中的行为与 int 不同

np.int64 behaves differently from int in math-operations

我遇到了一个非常奇怪的问题,我做了很多数学运算,当我的输入类型为 <class 'numpy.int64'> 时,结果是 infnan,但我得到当我的输入类型为 <class 'int'> 时,正确的(分析检查)结果。我使用的唯一库函数是 np.math.factorial()np.sum()np.array()。我还使用生成器对象对级数和来自 scipy.constants.

的玻尔兹曼常数求和

我的问题本质上是这样的:他们是否有任何已知案例,其中 np.int64 对象的行为与 int 对象的行为非常不同?

当我 运行 和 np.int64 输入时,我得到 RuntimeWarnings:overflow encountered in long_scalarsdivide by zero encountered in double_scalarsinvalid value encountered in double_scalars。但是,我插入阶乘函数的最大数字是 36,当我使用 int 输入时,我没有收到这些警告。

下面是重现该行为的代码。我无法更准确地找到它的来源。

import numpy as np
import scipy.constants as const

# Some representible numbers
sigma = np.array([1, 2])
sigma12 = 1.5
mole_weights = np.array([10,15])
T = 100
M1, M2 = mole_weights/np.sum(mole_weights)
m0 = np.sum(mole_weights)

fac = np.math.factorial

def summation(start, stop, func, args=None):
    #sum over the function func for all ints from start to and including stop, pass 'args' as additional arguments
    if args is not None:
        return sum(func(i, args) for i in range(start, stop + 1))
    else:
        return sum(func(i) for i in range(start, stop + 1))

def delta(i, j):
    #kronecker delta
    if i == j:
        return 1
    else:
        return 0

def w(l, r):
    # l,r are ints, return a float
    return 0.25 * (2 - ((1 / (l + 1)) * (1 + (-1) ** l))) * np.math.factorial(r + 1)

def omega(ij, l, r):
    # l, r are int, ij is and ID, returns float
    if ij in (1, 2):
        return sigma[ij - 1] ** 2 * np.sqrt(
            (np.pi * const.Boltzmann * T) / mole_weights[ij - 1]) * w(l, r)

    elif ij in (12, 21):
        return 0.5 * sigma12 ** 2 * np.sqrt(
            2 * np.pi * const.Boltzmann * T / (m0 * M1 * M2)) * w(l, r)
    else:
        raise ValueError('(' + str(ij) + ', ' + str(l) + ', ' + str(r) + ') are non-valid arguments for omega.')


def A_prime(p, q, r, l):
    '''
    p, q, r, l are ints. returns a float
    '''
    F = (M1 ** 2 + M2 ** 2) / (2 * M1 * M2)
    G = (M1 - M2) / M2

    def inner(w, args):
        i, k = args
        return ((8 ** i * fac(p + q - 2 * i - w) * (-1) ** (r + i) * fac(r + 1) * fac(
            2 * (p + q + 2 - i - w)) * 2 ** (2 * r) * F ** (i - k) * G ** w) /
                (fac(p - i - w) * fac(q - i - w) * fac(r - i) * fac(p + q + 1 - i - r - w) * fac(2 * r + 2) * fac(
                    p + q + 2 - i - w)
                 * 4 ** (p + q + 1) * fac(k) * fac(i - k) * fac(w))) * (
                       2 ** (2 * w - 1) * M1 ** i * M2 ** (p + q - i - w)) * 2 * (
                       M1 * (p + q + 1 - i - r - w) * delta(k, l) - M2 * (r - i) * delta(k, l - 1))

    def sum_w(k, i):
        return summation(0, min(p, q, p + q + 1 - r) - i, inner, args=(i, k))

    def sum_k(i):
        return summation(l - 1, min(l, i), sum_w, args=i)

    return summation(l - 1, min(p, q, r, p + q + 1 - r), sum_k)

def H_i(p, q):
    '''
    p, q are ints. Returns a float
    '''

    def inner(r, l):
        return A_prime(p, q, r, l) * omega(12, l, r)

    def sum_r(l):
        return summation(l, p + q + 2 - l, inner, args=l)

    val = 8 * summation(1, min(p, q) + 1, sum_r)

    return val

p, q = np.int64(8), np.int64(8)

print(H_i(p,q)) #nan
print(H_i(int(p) ,int(q))) #1.3480582058153066e-08
  • Numpy 的 int64 是一个 64 位整数,这意味着它由 64 个位置组成,要么是 0 要么是 1。因此最小的可表示值是 -2**63 最大的是 2**63 - 1
  • Python的int本质上是无限长度,所以它可以表示任何值。它相当于Java中的一个BigInteger。它存储为 int64 的列表,本质上被认为是一个大数字。

你这里的是经典integer overflow。您提到您“仅”将 36 代入阶乘函数,但阶乘函数增长 非常快 ,结果是 36! = 3.7e41 > 9.2e18 = 2**63 - 1,所以你得到的数字大于你可以用 int64 表示的数字!

由于 int64 也称为 longs 这正是警告 overflow encountered in long_scalars 试图告诉您的内容!