control overflow with a directive
authorRobert Bradshaw <robertwb@gmail.com>
Thu, 2 Aug 2012 03:21:53 +0000 (20:21 -0700)
committerRobert Bradshaw <robertwb@gmail.com>
Thu, 25 Oct 2012 05:49:44 +0000 (22:49 -0700)
Cython/Compiler/ExprNodes.py
Cython/Compiler/Options.py
Cython/Utility/Overflow.c

index 6cfc19e..c6225d4 100755 (executable)
@@ -8008,10 +8008,9 @@ class NumBinopNode(BinopNode):
             return
         if self.type.is_complex:
             self.infix = False
-        if self.type.is_int and self.operator in ('+', '-', '*', '/'):
+        if self.type.is_int and env.directives['overflowcheck'] and self.operator in ('+', '-', '*'):
             self.overflow_check = True
-            binop = {'+': 'add', '-': 'sub', '*': 'mul', '/': 'div'}[self.operator]
-            self.func = self.type.overflow_check_binop(binop, env)
+            self.func = self.type.overflow_check_binop(self.op_names[self.operator], env)
             self.is_temp = True
         if not self.infix or (type1.is_numeric and type2.is_numeric):
             self.operand1 = self.operand1.coerce_to(self.type, env)
@@ -8112,6 +8111,12 @@ class NumBinopNode(BinopNode):
         "%":        "PyNumber_Remainder",
         "**":       "PyNumber_Power"
     }
+    
+    op_names = {
+       "+":  "add",
+       "-":  "sub",
+       "*":  "mul",
+    }
 
 class IntBinopNode(NumBinopNode):
     #  Binary operation taking integer arguments.
index 764c886..8657633 100644 (file)
@@ -81,6 +81,7 @@ directive_defaults = {
     'auto_cpdef': False,
     'cdivision': False, # was True before 0.12
     'cdivision_warnings': False,
+    'overflowcheck': False,
     'always_allow_keywords': False,
     'allow_none_for_extension_args': True,
     'wraparound' : True,
index 00d0ff3..a71b4b2 100644 (file)
@@ -80,17 +80,18 @@ static CYTHON_INLINE {{UINT}} __Pyx_mul_{{NAME}}_checking_overflow({{UINT}} a, {
         unsigned long big_r = ((unsigned long) a) * ((unsigned long) b);
         {{UINT}} r = ({{UINT}}) big_r;
         *overflow |= big_r != r;
-        return ({{UINT}}) r;
+        return r;
     } else if (sizeof({{UINT}}) < sizeof(long long)) {
         unsigned long long big_r = ((unsigned long long) a) * ((unsigned long long) b);
         {{UINT}} r = ({{UINT}}) big_r;
         *overflow |= big_r != r;
-        return ({{UINT}}) r;
+        return r;
     } else {
         {{UINT}} prod = a * b;
         double dprod = ((double) a) * ((double) b);
-        // False positives.  Yes, the equality is required to avoid false negatives.
-        *overflow |= dprod >= (double) __PYX_MAX({{UINT}});
+        // Overflow results in an error of at least 2^sizeof(UINT),
+        // whereas rounding represents an error on the order of 2^(sizeof(UINT)-53).
+        *overflow |= fabs(dprod - prod) > (__PYX_MAX({{UINT}}) / 2);
         return prod;
     }
 }
@@ -128,22 +129,22 @@ static CYTHON_INLINE {{INT}} __Pyx_mul_const_{{NAME}}_checking_overflow({{INT}}
 
 /////////////// BaseCaseSigned ///////////////
 
-#define TOP_TWO_BITS(value, type) (value & ((unsigned type)3 << (sizeof(type) * 8 - 2)))
-
 static CYTHON_INLINE {{INT}} __Pyx_add_{{NAME}}_checking_overflow({{INT}} a, {{INT}} b, int *overflow) {
     if (sizeof({{INT}}) < sizeof(long)) {
         long big_r = ((long) a) + ((long) b);
         {{INT}} r = ({{INT}}) big_r;
         *overflow |= big_r != r;
-        return ({{INT}}) r;
+        return r;
     } else if (sizeof({{INT}}) < sizeof(long long)) {
         long long big_r = ((long long) a) + ((long long) b);
         {{INT}} r = ({{INT}}) big_r;
         *overflow |= big_r != r;
-        return ({{INT}}) r;
+        return r;
     } else {
-        // Signed overflow undefined, but unsigned is well defined.
+        // Signed overflow undefined, but unsigned overflow is well defined.
         {{INT}} r = ({{INT}}) ((unsigned {{INT}}) a + (unsigned {{INT}}) b);
+        // Overflow happened if the operands have the same sign, but the result
+        // has opposite sign.
         // sign(a) == sign(b) != sign(r)
         {{INT}} sign_a = __PYX_SIGN_BIT({{INT}}) & a;
         {{INT}} sign_b = __PYX_SIGN_BIT({{INT}}) & b;
@@ -186,8 +187,9 @@ static CYTHON_INLINE {{INT}} __Pyx_mul_{{NAME}}_checking_overflow({{INT}} a, {{I
     } else {
         {{INT}} prod = a * b;
         double dprod = ((double) a) * ((double) b);
-        // False positives.
-        *overflow |= fabs(dprod) > (double) __PYX_MAX({{INT}});
+        // Overflow results in an error of at least 2^sizeof(INT),
+        // whereas rounding represents an error on the order of 2^(sizeof(INT)-53).
+        *overflow |= fabs(dprod - prod) > (__PYX_MAX({{INT}}) / 2);
         return prod;
     }
 }