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

Python 在转换为32位整数后,Cython函数中的位被神秘地翻转,python,numpy,scipy,cython,Python,Numpy,Scipy,Cython,我有一个复杂的Cython函数,在过去的72小时里,它开始表现得非常奇怪 我们正在使用稀疏COO矩阵做一些事情,这需要在矩阵的COO表示的列索引上循环。因为我想快速完成这项工作,所以我将提取的列值粘贴到类型化C变量中,如下所示: ranked_groups = A[local_ranked,:].tocoo() ranked_groups_col_c = ranked_groups.col.astype(np.int32) >>> 280205 208621 >>

我有一个复杂的Cython函数,在过去的72小时里,它开始表现得非常奇怪

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

ranked_groups = A[local_ranked,:].tocoo()
ranked_groups_col_c = ranked_groups.col.astype(np.int32)
>>> 280205 208621
>>> 1120897 208621
>>> 891677560 208621
>>> 891677560 208621
奇怪的是,有时排名靠前的组的内容会变得混乱。也就是说,排名靠后的组列c应该只能包含从0到变量A列的值。例如,如果A是100x100,我们希望排名靠后的组列c的值在0到99之间

使用调试器,我已经确认了预投射变量ranked_组的列内容确实受到列计数的限制

虽然我们10次中有9次使用这种代码,但在我看来,在施法后排名组中的一些值看起来像是被随机置乱了位。例如,对于208621列的COO矩阵,我记录了如下案例:

ranked_groups = A[local_ranked,:].tocoo()
ranked_groups_col_c = ranked_groups.col.astype(np.int32)
>>> 280205 208621
>>> 1120897 208621
>>> 891677560 208621
>>> 891677560 208621
其中,第一个数字是排名组中的索引,该索引不应超过列数,第二个数字是源矩阵中的列数,仅供参考

我尝试将NumPy升级到最新版本和以前的版本,这种情况一直在发生。我们还联系了我们的云服务提供商,他们还没有回信。我不得不认为这是一些非常低级的bug,但我不清楚这可能是什么

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

# 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位宽的,不像x86_64 C编译器的int那样是32位宽的。如果一个64位Python整数在一台具有小尾数顺序的机器(如64位Intel)上被强制转换为32位,则高32位将被简单地截断,如果整数不大于231-1或小于-231,则高32位应全部为零或正整数或负整数。但是,如果出现较大的幅度整数,32位转换将导致错误。如果代码的C部分应该访问一个64位宽的Python整数数组作为一个32位整数数组,那么除了第0个元素的索引之外,其他所有元素都是错误的


在64位Linux和OSX安装上强制转换为long,还是在64位MS Windows安装上强制转换为long?

是否也可以发布cython代码,还是过于复杂或敏感?当你使用测试输入时,比如说,你例子中的100x100矩阵,你也会得到这样的结果吗?我会花一些时间来模糊代码的敏感部分,但我可以试着在问题中发布源代码。我们的测试套件使用较小的数据集,但没有出现故障。两周前使用此代码部署的一个映像上也没有出现这种情况,这就是为什么我认为这可能是一个机器问题。我怀疑如果没有代码,这是无法回答的,但是短期内,您至少可以展示一下ranked_groups_col_c是如何键入的吗?是的,这是一个64位的Python安装。我当然可以试着用一个长的来避免选角,但在我写这篇文章的时候,这看起来很傻。尽可能少地做可能安全!据我所知,将被强制转换的最大值是2^19阶。除了整数的大小之外,错误的索引(即,如果整数真的是64位宽的话,每32位在数组中期望一个新整数)是一个更普遍的问题。没有Cython密码是不可能的。但是,如果我理解正确的话,自动生成的Cython代码没有手动添加强制转换,它确实有效吗?是的,这真是一个奇怪的问题。我已经添加了我认为相关的代码片段,而不必担心意外共享太多。改变元素大小的问题与这个bug似乎是非确定性发生的事实并不完全一致。例如,在多个地方部署此代码时,同一函数调用会将不同的值转换为不同的值。