Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Gwenaël Samain
cython
Commits
a6bf4856
Commit
a6bf4856
authored
9 years ago
by
Stefan Behnel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
speed up (x % pyint)
parent
001ed48f
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
147 additions
and
21 deletions
+147
-21
CHANGES.rst
CHANGES.rst
+2
-1
Cython/Compiler/Optimize.py
Cython/Compiler/Optimize.py
+7
-0
Cython/Utility/Optimize.c
Cython/Utility/Optimize.c
+26
-12
tests/run/addop.pyx
tests/run/addop.pyx
+18
-2
tests/run/modop.pyx
tests/run/modop.pyx
+74
-6
tests/run/subop.pyx
tests/run/subop.pyx
+20
-0
No files found.
CHANGES.rst
View file @
a6bf4856
...
...
@@ -17,7 +17,8 @@ Features added
* Adding/subtracting constant Python floats and small integers is faster.
* Binary and/or/xor operations with small constant Python integers are faster.
* Binary and/or/xor operations and modulus with small constant Python integers
are faster.
Bugs fixed
----------
...
...
This diff is collapsed.
Click to expand it.
Cython/Compiler/Optimize.py
View file @
a6bf4856
...
...
@@ -2811,6 +2811,13 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin,
def
_handle_simple_method_object___xor__
(
self
,
node
,
function
,
args
,
is_unbound_method
):
return
self
.
_optimise_num_binop
(
'Xor'
,
node
,
function
,
args
,
is_unbound_method
)
def
_handle_simple_method_object___mod__
(
self
,
node
,
function
,
args
,
is_unbound_method
):
if
len
(
args
)
!=
2
or
not
isinstance
(
args
[
1
],
ExprNodes
.
IntNode
):
return
node
if
not
args
[
1
].
has_constant_result
()
or
not
(
2
<=
args
[
1
].
constant_result
<=
2
**
30
):
return
node
return
self
.
_optimise_num_binop
(
'Remainder'
,
node
,
function
,
args
,
is_unbound_method
)
def
_handle_simple_method_float___add__
(
self
,
node
,
function
,
args
,
is_unbound_method
):
return
self
.
_optimise_num_binop
(
'Add'
,
node
,
function
,
args
,
is_unbound_method
)
...
...
This diff is collapsed.
Click to expand it.
Cython/Utility/Optimize.c
View file @
a6bf4856
...
...
@@ -493,28 +493,32 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, long
#if CYTHON_COMPILING_IN_CPYTHON
{{
py
:
pyval
,
ival
=
(
'
op2
'
,
'b'
)
if
order
==
'
CObj
'
else
(
'
op1
'
,
'a'
)
}}
{{
py
:
c_op
=
{
'
Add
'
:
'+'
,
'
Subtract
'
:
'-'
,
'
Or
'
:
'|'
,
'
Xor
'
:
'^'
,
'
And
'
:
'&'
}[
op
]
}}
static
PyObject
*
__Pyx_PyInt_
{{
op
}}{{
order
}}(
PyObject
*
op1
,
PyObject
*
op2
,
long
intval
,
int
inplace
)
{
const
long
{{
'a'
if
order
==
'
CObj
'
else
'b'
}}
=
intval
;
{{
py
:
c_op
=
{
'
Add
'
:
'+'
,
'
Subtract
'
:
'-'
,
'
Remainder
'
:
'%'
,
'
Or
'
:
'|'
,
'
Xor
'
:
'^'
,
'
And
'
:
'&'
}[
op
]
}}
static
PyObject
*
__Pyx_PyInt_
{{
op
}}{{
order
}}(
PyObject
*
op1
,
PyObject
*
op2
,
CYTHON_UNUSED
long
intval
,
int
inplace
)
{
#if PY_MAJOR_VERSION < 3
if
(
likely
(
PyInt_CheckExact
({{
pyval
}})))
{
const
long
{{
'a'
if
order
==
'
CObj
'
else
'b'
}}
=
intval
;
{{
if
c_op
in
'
+-
'
}}
long
x
;
{{
endif
}}
long
{{
ival
}}
=
PyInt_AS_LONG
({{
pyval
}});
{{
if
c_op
not
in
'
+-
'
}}
// binary operators are safe, no overflow
return
PyInt_FromLong
(
a
{{
c_op
}}
b
);
{{
if
c_op
in
'
+-
'
}}
// adapted from intobject.c in Py2.7:
// casts in the line below avoid undefined behaviour on overflow
x
=
(
long
)((
unsigned
long
)
a
{{
c_op
}}
b
);
if
(
likely
((
x
^
a
)
>=
0
||
(
x
^
{{
'~'
if
op
==
'
Subtract
'
else
''
}}
b
)
>=
0
))
return
PyInt_FromLong
(
x
);
{{
else
}}
// adapted from intobject.c in Py2.7:
// casts in the line below avoid undefined behaviour on overflow
x
=
(
long
)((
unsigned
long
)
a
{{
c_op
}}
b
);
if
(
likely
((
x
^
a
)
>=
0
||
(
x
^
{{
'~'
if
op
==
'
Subtract
'
else
''
}}
b
)
>=
0
))
return
PyInt_FromLong
(
x
);
{{
if
c_op
==
'%'
}}
// modulus with differing signs isn't safely portable
if
(
unlikely
({{
ival
}}
<
0
))
return
(
inplace
?
PyNumber_InPlace
{{
op
}}
:
PyNumber_
{{
op
}})(
op1
,
op2
);
{{
endif
}}
// other operations are safe, no overflow
return
PyInt_FromLong
(
a
{{
c_op
}}
b
);
{{
endif
}}
return
PyLong_Type
.
tp_as_number
->
nb_
{{
op
.
lower
()}}(
op1
,
op2
);
...
...
@@ -523,11 +527,20 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, long
#if PY_MAJOR_VERSION >= 3 && CYTHON_USE_PYLONG_INTERNALS
if
(
likely
(
PyLong_CheckExact
({{
pyval
}})))
{
const
long
{{
'a'
if
order
==
'
CObj
'
else
'b'
}}
=
intval
;
long
{{
ival
}};
switch
(
Py_SIZE
({{
pyval
}}))
{
{{
if
c_op
!=
'%'
}}
case
-
1
:
{{
ival
}}
=
-
(
sdigit
)((
PyLongObject
*
){{
pyval
}})
->
ob_digit
[
0
];
break
;
{{
endif
}}
case
0
:
{{
ival
}}
=
0
;
break
;
case
1
:
{{
ival
}}
=
((
PyLongObject
*
){{
pyval
}})
->
ob_digit
[
0
];
break
;
case
2
:
if
(
8
*
sizeof
(
long
)
>
2
*
PyLong_SHIFT
)
{
{{
ival
}}
=
(
long
)
((((
unsigned
long
)((
PyLongObject
*
){{
pyval
}})
->
ob_digit
[
1
])
<<
PyLong_SHIFT
)
|
((
PyLongObject
*
){{
pyval
}})
->
ob_digit
[
0
]);
break
;
}
// fall through if two platform digits don't fit into a long
default:
return
PyLong_Type
.
tp_as_number
->
nb_
{{
op
.
lower
()}}(
op1
,
op2
);
}
return
PyLong_FromLong
(
a
{{
c_op
}}
b
);
...
...
@@ -536,6 +549,7 @@ static PyObject* __Pyx_PyInt_{{op}}{{order}}(PyObject *op1, PyObject *op2, long
{{
if
c_op
in
'
+-
'
}}
if
(
PyFloat_CheckExact
({{
pyval
}}))
{
const
long
{{
'a'
if
order
==
'
CObj
'
else
'b'
}}
=
intval
;
double
result
;
double
{{
ival
}}
=
PyFloat_AS_DOUBLE
({{
pyval
}});
// copied from floatobject.c in Py3.5:
...
...
This diff is collapsed.
Click to expand it.
tests/run/addop.pyx
View file @
a6bf4856
cimport
cython
def
bigint
(
x
):
print
(
str
(
x
).
rstrip
(
'L'
))
def
mixed_test
():
"""
>>> mixed_test()
...
...
@@ -29,6 +33,10 @@ def add_x_1(x):
2
>>> add_x_1(-1)
0
>>> bigint(2**50 + 1)
1125899906842625
>>> bigint(add_x_1(2**50))
1125899906842625
>>> add_x_1(1.5)
2.5
>>> add_x_1(-1.5)
...
...
@@ -73,13 +81,17 @@ def add_x_large(x):
-1073741824.0
>>> add_x_large(2**30 + 1)
2147483649
>>> bigint(2**50 + 1 + 2**30)
1125900980584449
>>> bigint(add_x_large(2**50 + 1))
1125900980584449
>>> 2**31 + 2**30
3221225472
>>> add_x_large(2**31)
3221225472
>>>
pr
int(2**66 + 2**30)
>>>
big
int(2**66 + 2**30)
73786976295911948288
>>>
pr
int(add_x_large(2**66))
>>>
big
int(add_x_large(2**66))
73786976295911948288
>>> try: add_x_large("abc")
... except TypeError: pass
...
...
@@ -96,6 +108,10 @@ def add_1_x(x):
2
>>> add_1_x(-1)
0
>>> bigint(2**50 + 1)
1125899906842625
>>> bigint(add_1_x(2**50))
1125899906842625
>>> add_1_x(1.5)
2.5
>>> add_1_x(-1.5)
...
...
This diff is collapsed.
Click to expand it.
tests/run/modop.pyx
View file @
a6bf4856
import
sys
if
sys
.
version_info
[
0
]
<
3
:
__doc__
=
u"""
>>> modptr()
'spameggs'
"""
def
modobj
(
obj2
,
obj3
):
"""
...
...
@@ -15,6 +11,73 @@ def modobj(obj2, obj3):
obj1
=
obj2
%
obj3
return
obj1
def
mod_obj_10
(
int2
):
"""
>>> 0 % 10
0
>>> mod_obj_10(0)
0
>>> 1 % 10
1
>>> mod_obj_10(1)
1
>>> 9 % 10
9
>>> mod_obj_10(9)
9
>>> 10 % 10
0
>>> mod_obj_10(10)
0
>>> 10002 % 10
2
>>> mod_obj_10(10002)
2
>>> int((2**50) % 10)
4
>>> int(mod_obj_10(2**50))
4
>>> int((2**200) % 10)
6
>>> int(mod_obj_10(2**200))
6
>>> (-1) % 10
9
>>> mod_obj_10(-1)
9
>>> (-10) % 10
0
>>> mod_obj_10(-10)
0
>>> (-12) % 10
8
>>> mod_obj_10(-12)
8
"""
int1
=
int2
%
10
return
int1
def
mod_obj_m2
(
int2
):
"""
>>> 0 % -2
0
>>> mod_obj_m2(0)
0
>>> 1 % -2
-1
>>> mod_obj_m2(1)
-1
>>> 9 % -2
-1
>>> mod_obj_m2(9)
-1
"""
int1
=
int2
%
-
2
return
int1
def
modint
(
int
int2
,
int
int3
):
"""
>>> modint(9,2)
...
...
@@ -24,9 +87,14 @@ def modint(int int2, int int3):
int1
=
int2
%
int3
return
int1
def
modptr
():
"""
>>> print(modptr() if sys.version_info[0] < 3 else 'spameggs')
spameggs
"""
cdef
char
*
str2
,
*
str3
str2
=
"spam%s"
str3
=
"eggs"
obj1
=
str2
%
str3
# '%' operator doesn't work on byte strings in Py3
obj1
=
str2
%
str3
# '%' operator doesn't work on byte strings in Py3
return
obj1
This diff is collapsed.
Click to expand it.
tests/run/subop.pyx
View file @
a6bf4856
cimport
cython
def
bigint
(
x
):
print
(
str
(
x
).
rstrip
(
'L'
))
def
mixed_test
():
"""
>>> mixed_test()
...
...
@@ -44,6 +48,10 @@ def sub_x_1(x):
0
>>> sub_x_1(-1)
-2
>>> bigint(2**50 - 1)
1125899906842623
>>> bigint(sub_x_1(2**50))
1125899906842623
>>> sub_x_1(1.5)
0.5
>>> sub_x_1(-1.5)
...
...
@@ -63,6 +71,10 @@ def sub_x_1f(x):
0.0
>>> sub_x_1f(-1)
-2.0
>>> 2**50 - 1.0
1125899906842623.0
>>> sub_x_1f(2**50)
1125899906842623.0
>>> sub_x_1f(1.5)
0.5
>>> sub_x_1f(-1.5)
...
...
@@ -82,6 +94,10 @@ def sub_x_large(x):
-1073741823
>>> sub_x_large(-1)
-1073741825
>>> bigint(2**50 - 2**30)
1125898833100800
>>> bigint(sub_x_large(2**50))
1125898833100800
>>> sub_x_large(2.0**30)
0.0
>>> sub_x_large(2.0**30 + 1)
...
...
@@ -107,6 +123,10 @@ def sub_1_x(x):
2
>>> sub_1_x(1)
0
>>> bigint(1 - 2**50)
-1125899906842623
>>> bigint(sub_1_x(2**50))
-1125899906842623
>>> sub_1_x(1.5)
-0.5
>>> sub_1_x(-1.5)
...
...
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment