Commit 2c823b74 authored by Stefan Behnel's avatar Stefan Behnel

Special-case some arithmetic operations with 0 that can be implemented without...

Special-case some arithmetic operations with 0 that can be implemented without creating new objects.
parent 6d9daa08
...@@ -891,8 +891,27 @@ static {{c_ret_type}} __Pyx_PyInt_{{'' if ret_type.is_pyobject else 'Bool'}}{{op ...@@ -891,8 +891,27 @@ static {{c_ret_type}} __Pyx_PyInt_{{'' if ret_type.is_pyobject else 'Bool'}}{{op
// special case for &-ing arbitrarily large numbers with known single digit operands // special case for &-ing arbitrarily large numbers with known single digit operands
if ((intval & PyLong_MASK) == intval) { if ((intval & PyLong_MASK) == intval) {
return PyLong_FromLong(likely(size) ? digits[0] & intval : 0); return PyLong_FromLong(likely(size) ? digits[0] & intval : 0);
} else }
{{endif}} {{endif}}
// special cases for 0: + - % / // | ^ & >> <<
if (unlikely(size == 0)) {
{{if order == 'CObj' and c_op in '+-|^>><<'}}
// x == x+0 == x-0 == x|0 == x^0 == x>>0 == x<<0
return __Pyx_NewRef(op1);
{{elif order == 'CObj' and c_op in '&'}}
// 0 == x&0
return __Pyx_NewRef(op2);
{{elif order == 'ObjC' and c_op in '+|^'}}
// x == 0+x == 0|x == 0^x
return __Pyx_NewRef(op2);
{{elif order == 'ObjC' and c_op == '-'}}
// -x == 0-x
return PyLong_FromLong(-intval);
{{elif order == 'ObjC' and (c_op in '%&>><<' or op == 'FloorDivide')}}
// 0 == 0%x == 0&x == 0>>x == 0<<x == 0//x
return __Pyx_NewRef(op1);
{{endif}}
}
// handle most common case first to avoid indirect branch and optimise branch prediction // handle most common case first to avoid indirect branch and optimise branch prediction
if (likely(__Pyx_sst_abs(size) <= 1)) { if (likely(__Pyx_sst_abs(size) <= 1)) {
{{ival}} = likely(size) ? digits[0] : 0; {{ival}} = likely(size) ? digits[0] : 0;
......
...@@ -166,3 +166,17 @@ def add_large_x(x): ...@@ -166,3 +166,17 @@ def add_large_x(x):
... except TypeError: pass ... except TypeError: pass
""" """
return 2**30 + x return 2**30 + x
def add0(x):
"""
>>> add0(0)
(0, 0)
>>> add0(1)
(1, 1)
>>> add0(-1)
(-1, -1)
>>> add0(2**32)
(4294967296, 4294967296)
"""
return x + 0, 0 + x
...@@ -12,6 +12,28 @@ def modobj(obj2, obj3): ...@@ -12,6 +12,28 @@ def modobj(obj2, obj3):
return obj1 return obj1
def mod_10_obj(int2):
"""
>>> mod_10_obj(0)
Traceback (most recent call last):
ZeroDivisionError: integer division or modulo by zero
>>> 10 % 1
0
>>> mod_10_obj(1)
0
>>> mod_10_obj(3)
1
>>> 10 % -1
0
>>> mod_10_obj(-1)
0
>>> mod_10_obj(-10)
0
"""
int1 = 10 % int2
return int1
def mod_obj_10(int2): def mod_obj_10(int2):
""" """
>>> 0 % 10 >>> 0 % 10
......
...@@ -25,6 +25,8 @@ def or_obj(obj2, obj3): ...@@ -25,6 +25,8 @@ def or_obj(obj2, obj3):
@cython.test_fail_if_path_exists('//IntBinopNode') @cython.test_fail_if_path_exists('//IntBinopNode')
def or_int(obj2): def or_int(obj2):
""" """
>>> or_int(0)
16
>>> or_int(1) >>> or_int(1)
17 17
>>> or_int(16) >>> or_int(16)
...@@ -47,6 +49,8 @@ def xor_obj(obj2, obj3): ...@@ -47,6 +49,8 @@ def xor_obj(obj2, obj3):
@cython.test_fail_if_path_exists('//IntBinopNode') @cython.test_fail_if_path_exists('//IntBinopNode')
def xor_int(obj2): def xor_int(obj2):
""" """
>>> xor_int(0)
16
>>> xor_int(2) >>> xor_int(2)
18 18
>>> xor_int(16) >>> xor_int(16)
...@@ -69,6 +73,8 @@ def and_obj(obj2, obj3): ...@@ -69,6 +73,8 @@ def and_obj(obj2, obj3):
@cython.test_fail_if_path_exists('//IntBinopNode') @cython.test_fail_if_path_exists('//IntBinopNode')
def and_int(obj2): def and_int(obj2):
""" """
>>> and_int(0)
0
>>> and_int(1) >>> and_int(1)
0 0
>>> and_int(18) >>> and_int(18)
...@@ -98,9 +104,30 @@ def rshift_obj(obj2, obj3): ...@@ -98,9 +104,30 @@ def rshift_obj(obj2, obj3):
return obj1 return obj1
@cython.test_assert_path_exists('//IntBinopNode')
def rshift_int_obj(obj3):
"""
>>> rshift_int_obj(3)
0
>>> rshift_int_obj(2)
0
>>> rshift_int_obj(1)
1
>>> rshift_int_obj(0)
2
>>> rshift_int_obj(-1)
Traceback (most recent call last):
ValueError: negative shift count
"""
obj1 = 2 >> obj3
return obj1
@cython.test_fail_if_path_exists('//IntBinopNode') @cython.test_fail_if_path_exists('//IntBinopNode')
def rshift_int(obj2): def rshift_int(obj2):
""" """
>>> rshift_int(0)
0
>>> rshift_int(2) >>> rshift_int(2)
0 0
...@@ -226,6 +253,8 @@ def mixed_obj(obj2, obj3): ...@@ -226,6 +253,8 @@ def mixed_obj(obj2, obj3):
) )
def mixed_int(obj2): def mixed_int(obj2):
""" """
>>> mixed_int(0)
16
>>> mixed_int(2) >>> mixed_int(2)
18 18
>>> mixed_int(16) >>> mixed_int(16)
......
...@@ -191,3 +191,21 @@ def sub_large_x(x): ...@@ -191,3 +191,21 @@ def sub_large_x(x):
... except TypeError: pass ... except TypeError: pass
""" """
return 2**30 - x return 2**30 - x
def sub0(x):
"""
>>> sub0(0)
(0, 0)
>>> sub0(1)
(1, -1)
>>> sub0(-1)
(-1, 1)
>>> sub0(99)
(99, -99)
>>> sub0(2**32)
(4294967296, -4294967296)
>>> sub0(-2**32)
(-4294967296, 4294967296)
"""
return x - 0, 0 - x
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment