iTayb
iTayb

Reputation: 12753

Cython returns 0 for expression that should evaluate to 0.5?

For some reason, Cython is returning 0 on a math expression that should evaluate to 0.5:

print(2 ** (-1))  # prints 0

Oddly enough, mix variables in and it'll work as expected:

i = 1
print(2 ** (-i))  # prints 0.5

Vanilla CPython returns 0.5 for both cases. I'm compiling for 37m-x86_64-linux-gnu, and language_level is set to 3.

What is this witchcraft?

Upvotes: 8

Views: 203

Answers (2)

DavidW
DavidW

Reputation: 30916

It's because it's using C ints rather than Python integers so it matches C behaviour rather than Python behaviour. I'm relatively sure this used to be documented as a limitation somewhere but I can't find it now. If you want to report it as a bug then go to https://github.com/cython/cython/issues, but I suspect this is a deliberate trade-off of speed for compatibility.

The code gets translated to

__Pyx_pow_long(2, -1L)

where __Pyx_pow_long is a function of type static CYTHON_INLINE long __Pyx_pow_long(long b, long e).


The easiest way to fix it is to change one/both of the numbers to be a floating point number

 print(2. ** (-1))

As a general comment on the design choice: people from the C world generally expect int operator int to return an int, and this option will be fastest. Python had tried to do this in the past with the Python 2 division behaviour (but inconsistently - power always returned a floating point number).

Cython generally tries to follow Python behaviour. However, a lot of people are using it for speed so they also try to fall back to quick, C-like operations especially when people specify types (since those people want speed). I think what's happened here is that it's been able to infer the types automatically, and so defaulted to C behaviour. I suspect ideally it should distinguish between specified types and types that it's inferred. However, it's also probably too late to start changing that.

Upvotes: 4

Emrah Diril
Emrah Diril

Reputation: 1765

It looks like Cython is incorrectly inferring the final data type as int rather than float when only numbers are involved

The following code works as expected:

print(2.0 ** (-1))

See this link for a related discussion: https://groups.google.com/forum/#!topic/cython-users/goVpote2ScY

Upvotes: 2

Related Questions