在转换为 32 位整数后神秘地翻转了 Cython 函数中的位



我有一个繁琐的Cython函数,它在过去72小时内开始表现得非常奇怪。

我们正在使用稀疏的 COO 矩阵做一些事情,这些矩阵需要遍历矩阵的 COO 表示形式的列索引。因为我想快速完成此操作,所以我将提取的列值粘贴到类型化的 C 变量中,如下所示:

ranked_groups = A[local_ranked,:].tocoo()
ranked_groups_col_c = ranked_groups.col.astype(np.int32)

奇怪的是,有时ranked_groups_col_c的内容会被打乱。也就是说,ranked_groups_col_c应该只能包含从 0 到变量A的列的值。例如,如果 A 为 100x100,我们期望ranked_groups_col_c的值介于 0 和 99 之间。

使用调试器,我确认预制变量ranked_groups的列内容确实受列计数的限制。

虽然我们使用此代码的 10 次中大约有 9 次,但在我看来,ranked_groups_col_c中的某些值(转换后(看起来像是随机加扰了位。例如,对于包含 208621 列的 COO 矩阵,我记录了如下情况:

>>> 280205 208621
>>> 1120897 208621
>>> 891677560 208621
>>> 891677560 208621

其中第一个数字是ranked_groups_col_c中的索引(不应超出列计数(,第二个数字是源矩阵中的列数以供参考。

我尝试将NumPy升级到最新版本和过去的版本,这种情况一直在发生。我们也联系了我们的云提供商,他们没有回信。我不得不认为这是一个非常低级的错误,但我不清楚那可能是什么。

更新:我们对发布整个函数有点犹豫,但这里有一个包含变量声明的代码片段:

# the matrix A is an argument of the function
ranked = np.argsort(-scores).astype(np.int32)
seen = np.zeros(A.shape[1], dtype=np.int32)
cdef int[:] seen_c = seen
cdef int[:] local_ranked_c
cdef int[:] ranked_groups_col_c
for i in range(n):
local_ranked = ranked[i,:]
local_ranked_c = local_ranked
ranked_groups = A[local_ranked,:].tocoo()
ranked_groups_col_c = ranked_groups.col.astype(np.int32)
for pos in range(m):
j = local_ranked_c[pos]
k = ranked_groups_col_c[pos]
if seen_c[k]:
pass

根据 Python 安装(即它是 64 位安装吗?(,转换为 32 位整数可能会出现问题。对于 64 位 Python 解释器,整数是 64 位宽的(不像int例如 x86_64 C 编译器是 32 位宽(。如果在具有很少端序排序的机器(例如 64 位 Intel(上将单个 64 位 Python 整数转换为 32 位,则 32 位较高位将被简单地切掉,如果整数不大于 2 31-1 或小于 -231(较高的位应该都是零或正整数或负整数的 1(。但是,如果出现较大的幅度整数,则 32 位转换将导致错误。如果代码的 C 部分应将 64 位宽的 Python 整数数组作为 32 位整数数组访问,则除了第 0 个元素的索引之外的所有元素都是错误的。

是否可以在 Linux 和 OSX 的 64 位安装上强制转换为long,或者在 64 位 MS Windows 安装上转换为long long

最新更新