Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exponentiation of integer constants interpreted as integer #2133

Closed
timostrunk opened this issue Mar 6, 2018 · 2 comments
Closed

Exponentiation of integer constants interpreted as integer #2133

timostrunk opened this issue Mar 6, 2018 · 2 comments

Comments

@timostrunk
Copy link

Problem

When specifying numeric constants with the unusual syntax:
10 ** -1
cython most probably inteprets the result as integer, while the python interpreter interprets it as float.
This only affects constants and does not affect variables.

Minimal Example

Code

test.pyx / test.py

print (10 ** -1)
print (1E-1)
a = 10
print (a ** -1)

setup.py

from distutils.core import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("test.pyx")
)

Compilation

python ./setup.py build_ext --inplace

Results

python -c "import test" # with uncompiled test.py

0.1
0.1
0.1

python -c "import test" # with compiled test.pyx

0
0.1
0.1
@scoder scoder added this to the 0.29 milestone Mar 6, 2018
@scoder
Copy link
Contributor

scoder commented Mar 6, 2018

A bit of an edge case, but I'm inclined to agree. If one of the two operands is a (typed) variable, the result type depends on the variable type. If both sides are literals, however, it should follow Python code semantics, which means that the result is either an arbitrary size non-negative integer or a double float. And that needs to be decided at compile time, as C is quite picky about types. ;)

This can still get tricky when the actual code is something like 10 ** (1-2), i.e. the right side is an expression rather than a literal, maybe even one that cannot safely be evaluated at compile time. Specifically, Cython does not currently do that for constant float expressions in order to avoid loss (or gain) of precision on string serialisation, so 10 ** -1 is actually not folded into a literal 0.1 in the C code.

The problem with literal IEEE-754 float expressions is really that some users might be spelling them out in a specific way (instead of using literals) because they actually rely on the exact semantics, so evaluating them at compile time with any semantics that are not strictly IEEE-754 (such as fractions.Fraction()) is straight out, and even evaluating them as Python floats and then using repr() to write them into the C code might not result in exactly the binary double float in C that users expected from the specific expression they wrote.

Long story short, I think what needs to be done is what CPython does here: if the exponent is negative, coerce both operands to double floats and evaluate the whole expression as double. For numeric literal expressions, the sign should always be available at compile time via internal constant calculation. See PowNode and its base classes in ExprNodes.py.

@gabrieldemarmiesse
Copy link
Contributor

I'll note here for whoever wants to fix this issue the places in the documentation that will need to be changed accordingly:

https://github.com/cython/cython/blob/master/docs/src/tutorial/caveats.rst#caveats

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants