ARN
ARN

Reputation: 111

Bizarre integer behavior in cython

I'm running into a strange issue with some integer manipulation in cython. When I compile this cython code ...

test.pyx

from libc.math cimport abs

cdef int c = 2047
cdef int b = 1009
print('%d'%(-(abs(b)&c)))

...like this

#!python
from subprocess import check_output

CFLAGS = check_output('python-config --cflags'.split()).decode('utf-8').strip()
LDFLAGS = check_output('python-config --ldflags'.split()).decode('utf-8').strip()

check_output('cython test.pyx'.split())

compile_call = ('clang -c test.c %s'%(CFLAGS)).split()
check_output(compile_call)

link_call = ('clang test.o -o test.so -shared %s'%(LDFLAGS)).split()
check_output(link_call)

import test

...I get 2130706744, but the right answer is -1009.

Upvotes: 4

Views: 239

Answers (1)

ARN
ARN

Reputation: 111

Looks like this might be a bug in Cython. The relevant line in test.c is

__pyx_t_2 = __Pyx_PyInt_From_unsigned_int((-(__pyx_t_1 & __pyx_v_4test_c)));

Clearly interpreting our number as unsigned gives a wrong answer. However if I remove the abs call, then I get

__pyx_t_1 = __Pyx_PyInt_From_int((-(__pyx_v_4test_b & __pyx_v_4test_c)));

and the result is correct. If I add a cast to int like print('%d'%(-(<int>abs(b)&c))) then I also get the right answer.

Cross posted to the Cython github page

Update: Here is the response to my github issue:

Basically, a signed int is not large enough to hold abs(-MAX_INT-1), so the result was changed to return an unsigned value. On the other hand, I agree that using an unsigned value is quite confusing as well, especially as promotion of equally ranked integers is to the unsigned type so it's contagious. Unclear what the best course of action is here...

Upvotes: 2

Related Questions