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
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
nexedi
cython
Commits
52099c3e
Commit
52099c3e
authored
May 03, 2014
by
Stefan Behnel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
speed up Python object calculation of 2**N
parent
39bf23cc
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
99 additions
and
11 deletions
+99
-11
CHANGES.rst
CHANGES.rst
+2
-0
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+23
-11
Cython/Utility/Optimize.c
Cython/Utility/Optimize.c
+41
-0
tests/run/powop.pyx
tests/run/powop.pyx
+33
-0
No files found.
CHANGES.rst
View file @
52099c3e
...
...
@@ -9,6 +9,8 @@ Latest
Features added
--------------
* The Python expression "2 ** N" was optimised.
* Simple support for declaring Python object types in Python signature
annotations. Currently requires setting the compiler directive
``annotation_typing=True``.
...
...
Cython/Compiler/ExprNodes.py
View file @
52099c3e
...
...
@@ -8111,7 +8111,7 @@ class UnopNode(ExprNode):
self
.
generate_py_operation_code
(
code
)
def
generate_py_operation_code
(
self
,
code
):
function
=
self
.
py_operation_function
()
function
=
self
.
py_operation_function
(
code
)
code
.
putln
(
"%s = %s(%s); %s"
%
(
self
.
result
(),
...
...
@@ -8187,7 +8187,7 @@ class UnaryPlusNode(UnopNode):
self
.
type
=
PyrexTypes
.
widest_numeric_type
(
self
.
operand
.
type
,
PyrexTypes
.
c_int_type
)
def
py_operation_function
(
self
):
def
py_operation_function
(
self
,
code
):
return
"PyNumber_Positive"
def
calculate_result_code
(
self
):
...
...
@@ -8213,7 +8213,7 @@ class UnaryMinusNode(UnopNode):
if
self
.
type
.
is_complex
:
self
.
infix
=
False
def
py_operation_function
(
self
):
def
py_operation_function
(
self
,
code
):
return
"PyNumber_Negative"
def
calculate_result_code
(
self
):
...
...
@@ -8239,7 +8239,7 @@ class TildeNode(UnopNode):
else
:
self
.
type_error
()
def
py_operation_function
(
self
):
def
py_operation_function
(
self
,
code
):
return
"PyNumber_Invert"
def
calculate_result_code
(
self
):
...
...
@@ -8874,6 +8874,7 @@ def get_compile_time_binop(node):
%
node
.
operator
)
return
func
class
BinopNode
(
ExprNode
):
# operator string
# operand1 ExprNode
...
...
@@ -8990,7 +8991,7 @@ class BinopNode(ExprNode):
def
generate_result_code
(
self
,
code
):
#print "BinopNode.generate_result_code:", self.operand1, self.operand2 ###
if
self
.
operand1
.
type
.
is_pyobject
:
function
=
self
.
py_operation_function
()
function
=
self
.
py_operation_function
(
code
)
if
self
.
operator
==
'**'
:
extra_args
=
", Py_None"
else
:
...
...
@@ -9024,7 +9025,7 @@ class CBinopNode(BinopNode):
node
.
type
=
PyrexTypes
.
error_type
return
node
def
py_operation_function
(
self
):
def
py_operation_function
(
self
,
code
):
return
""
def
calculate_result_code
(
self
):
...
...
@@ -9162,7 +9163,7 @@ class NumBinopNode(BinopNode):
type2
.
is_unicode_char
or
BinopNode
.
is_py_operation_types
(
self
,
type1
,
type2
))
def
py_operation_function
(
self
):
def
py_operation_function
(
self
,
code
):
function_name
=
self
.
py_functions
[
self
.
operator
]
if
self
.
inplace
:
function_name
=
function_name
.
replace
(
'PyNumber_'
,
'PyNumber_InPlace'
)
...
...
@@ -9228,7 +9229,7 @@ class AddNode(NumBinopNode):
return
NumBinopNode
.
compute_c_result_type
(
self
,
type1
,
type2
)
def
py_operation_function
(
self
):
def
py_operation_function
(
self
,
code
):
type1
,
type2
=
self
.
operand1
.
type
,
self
.
operand2
.
type
if
type1
is
unicode_type
or
type2
is
unicode_type
:
if
type1
.
is_builtin_type
and
type2
.
is_builtin_type
:
...
...
@@ -9236,7 +9237,7 @@ class AddNode(NumBinopNode):
return
'__Pyx_PyUnicode_ConcatSafe'
else
:
return
'__Pyx_PyUnicode_Concat'
return
super
(
AddNode
,
self
).
py_operation_function
()
return
super
(
AddNode
,
self
).
py_operation_function
(
code
)
class
SubNode
(
NumBinopNode
):
...
...
@@ -9499,7 +9500,7 @@ class ModNode(DivNode):
self
.
operand1
.
result
(),
self
.
operand2
.
result
())
def
py_operation_function
(
self
):
def
py_operation_function
(
self
,
code
):
if
self
.
operand1
.
type
is
unicode_type
:
if
self
.
operand1
.
may_be_none
():
return
'__Pyx_PyUnicode_FormatSafe'
...
...
@@ -9510,7 +9511,7 @@ class ModNode(DivNode):
return
'__Pyx_PyString_FormatSafe'
else
:
return
'__Pyx_PyString_Format'
return
super
(
ModNode
,
self
).
py_operation_function
()
return
super
(
ModNode
,
self
).
py_operation_function
(
code
)
class
PowNode
(
NumBinopNode
):
...
...
@@ -9551,6 +9552,17 @@ class PowNode(NumBinopNode):
typecast
(
self
.
operand1
),
typecast
(
self
.
operand2
))
def
py_operation_function
(
self
,
code
):
if
(
self
.
type
.
is_pyobject
and
self
.
operand1
.
constant_result
==
2
and
self
.
operand2
.
type
is
py_object_type
):
code
.
globalstate
.
use_utility_code
(
UtilityCode
.
load_cached
(
'PyNumberPow2'
,
'Optimize.c'
))
if
self
.
inplace
:
return
'__Pyx_PyNumber_InPlacePowerOf2'
else
:
return
'__Pyx_PyNumber_PowerOf2'
return
super
(
PowNode
,
self
).
py_operation_function
(
code
)
# Note: This class is temporarily "shut down" into an ineffective temp
# allocation mode.
...
...
Cython/Utility/Optimize.c
View file @
52099c3e
...
...
@@ -421,3 +421,44 @@ static double __Pyx__PyObject_AsDouble(PyObject* obj) {
bad:
return
(
double
)
-
1
;
}
/////////////// PyNumberPow2.proto ///////////////
#define __Pyx_PyNumber_InPlacePowerOf2(a, b, c) __Pyx__PyNumber_PowerOf2(a, b, c, 1)
#define __Pyx_PyNumber_PowerOf2(a, b, c) __Pyx__PyNumber_PowerOf2(a, b, c, 0)
static
PyObject
*
__Pyx__PyNumber_PowerOf2
(
PyObject
*
two
,
PyObject
*
exp
,
PyObject
*
none
,
int
inplace
);
/*proto*/
/////////////// PyNumberPow2 ///////////////
static
PyObject
*
__Pyx__PyNumber_PowerOf2
(
PyObject
*
two
,
PyObject
*
exp
,
PyObject
*
none
,
int
inplace
)
{
// in CPython, 1<<N is substantially faster than 2**N
// TODO: disable this in Py3.5 if http://bugs.python.org/issue21420 gets accepted
#if CYTHON_COMPILING_IN_CPYTHON
Py_ssize_t
shiftby
;
if
(
likely
(
PyLong_Check
(
exp
)))
{
shiftby
=
PyLong_AsSsize_t
(
exp
);
#if PY_MAJOR_VERSION < 3
}
else
if
(
likely
(
PyInt_Check
(
exp
)))
{
shiftby
=
PyInt_AsLong
(
exp
);
#endif
}
else
{
goto
fallback
;
}
if
(
likely
(
shiftby
>=
0
))
{
if
((
size_t
)
shiftby
<=
sizeof
(
long
)
*
8
-
2
)
{
long
value
=
1L
<<
shiftby
;
return
PyInt_FromLong
(
value
);
}
else
{
PyObject
*
one
=
PyInt_FromLong
(
1L
);
if
(
unlikely
(
!
one
))
return
NULL
;
return
PyNumber_Lshift
(
one
,
exp
);
}
}
else
if
(
shiftby
==
-
1
&&
PyErr_Occurred
())
{
PyErr_Clear
();
}
fallback:
#endif
return
(
inplace
?
PyNumber_InPlacePower
:
PyNumber_Power
)(
two
,
exp
,
none
);
}
tests/run/powop.pyx
View file @
52099c3e
...
...
@@ -10,6 +10,7 @@ def f(obj2, obj3):
obj1
=
obj2
**
obj3
return
flt1
,
obj1
def
g
(
i
):
"""
>>> g(4)
...
...
@@ -17,6 +18,7 @@ def g(i):
"""
return
i
**
5
def
h
(
i
):
"""
>>> h(4)
...
...
@@ -24,6 +26,7 @@ def h(i):
"""
return
5
**
i
def
constant_py
():
"""
>>> constant_py() == 2 ** 10
...
...
@@ -32,6 +35,7 @@ def constant_py():
result
=
(
<
object
>
2
)
**
10
return
result
def
constant_long
():
"""
>>> constant_long() == 2 ** 36
...
...
@@ -40,6 +44,7 @@ def constant_long():
result
=
(
<
object
>
2L
)
**
36
return
result
def
small_int_pow
(
long
s
):
"""
>>> small_int_pow(3)
...
...
@@ -49,6 +54,7 @@ def small_int_pow(long s):
"""
return
s
**
0
,
s
**
1
,
s
**
2
,
s
**
3
,
s
**
4
def
int_pow
(
short
a
,
short
b
):
"""
>>> int_pow(7, 2)
...
...
@@ -59,3 +65,30 @@ def int_pow(short a, short b):
1024
"""
return
a
**
b
def
optimised_pow2
(
n
):
"""
>>> optimised_pow2(0)
1
>>> optimised_pow2(1)
2
>>> optimised_pow2(10)
1024
>>> optimised_pow2(30)
1073741824
>>> print(repr(optimised_pow2(32)).rstrip('L'))
4294967296
>>> print(repr(optimised_pow2(100)).rstrip('L'))
1267650600228229401496703205376
>>> optimised_pow2(30000) == 2 ** 30000
True
>>> optimised_pow2(-1)
0.5
>>> optimised_pow2(0.5) == 2 ** 0.5
True
>>> optimised_pow2('test')
Traceback (most recent call last):
TypeError: unsupported operand type(s) for ** or pow(): 'int' and 'str'
"""
return
2
**
n
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