Таинственно перевернутые биты в функции Cython после приведения к 32-битному целому числу - PullRequest
0 голосов
/ 29 сентября 2019

У меня сложная функция 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.

Используя отладчик, я подтвердил, что содержимое столбца переменной pre-cast ranked_groups действительно ограничены числом столбцов.

В то время как примерно в 9 из 10 раз мы используем этот код, некоторые значения в ranked_groups_col_c (после приведения) выглядят так, как будто биты были случайно зашифрованы,Например, с матрицей COO из 208621 столбцов я записал в журнал такие случаи:

>>> 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

1 Ответ

1 голос
/ 29 сентября 2019

В зависимости от установки Python (т.е. это 64-разрядная установка?) Могут возникнуть проблемы с приведением к 32-разрядным целым числам. Для 64-битного интерпретатора Python целые числа имеют ширину 64 бита (в отличие от int, например, для компиляторов x86_64 C, которые имеют ширину 32 бита). Если одно 64-битное целое число Python преобразуется в 32 бита на машине с порядком байтов (например, 64-битным Intel), то старшие 32 бита просто обрезаются, что хорошо, если целое число не больше 2 31 -1 или меньше -2 31 (тогда старшие биты должны быть нулями или единицами для положительных или отрицательных целых чисел). Однако, если возникнут целые числа большей величины, 32-битное преобразование приведет к ошибкам. Если часть кода C должна обращаться к массиву 32-битных целых чисел Python шириной 64, как к массиву 32-битных целых, все, кроме индекса нулевого элемента, будут неправильными.

Приведение к long в 64-разрядных установках Linux и OSX или long long в 64-разрядных установках MS Windows - вариант?

...