Repository: pandas-dev/pandas

Issue:
BUG: div by integer 0 returning non-signed infs (and nan issue)
#6149

exposed this bug; going to update the tests (and i'll link there that show it)
initially only showed up on py2.6...but it is real

the signs of the inf under integer division are wrong.
for the most part the np.nan are preserved, not sure if this is right or not

```
In [1]: Series([np.nan,1,-1])/0
Out[1]: 
0    inf
1    inf
2    inf
dtype: float64

In [2]: Series([np.nan,1,-1])/0.
Out[2]: 
0    NaN
1    inf
2   -inf
dtype: float64
```



Discussion:
cc @jtratner this is an issue on `com._fill_zeros` it needs to figure out the sign of the resultant expression (easy), but the rops seems to fail for some reason

this fixes for series; problem on frame/panel (but only on rops)

https://github.com/jreback/pandas/tree/int_div


Resolving patch:
diff --git a/pandas/core/common.py b/pandas/core/common.py
--- a/pandas/core/common.py
+++ b/pandas/core/common.py
@@ -1179,13 +1179,23 @@ def _lcd_dtypes(a_dtype, b_dtype):
     return np.object
 
 
-def _fill_zeros(result, y, fill):
-    """ if we have an integer value (or array in y)
+def _fill_zeros(result, x, y, name, fill):
+    """
+    if this is a reversed op, then flip x,y
+
+    if we have an integer value (or array in y)
     and we have 0's, fill them with the fill,
     return the result
+
+    mask the nan's from x
     """
 
     if fill is not None:
+
+        if name.startswith('r'):
+            x,y = y,x
+
+
         if not isinstance(y, np.ndarray):
             dtype, value = _infer_dtype_from_scalar(y)
             y = pa.empty(result.shape, dtype=dtype)
@@ -1196,8 +1206,18 @@ def _fill_zeros(result, y, fill):
             mask = y.ravel() == 0
             if mask.any():
                 shape = result.shape
-                result, changed = _maybe_upcast_putmask(
-                    result.ravel(), mask, fill)
+                result = result.ravel().astype('float64')
+
+                signs = np.sign(result)
+                nans = np.isnan(x.ravel())
+                np.putmask(result, mask & ~nans, fill)
+
+                # if we have a fill of inf, then sign it
+                # correctly
+                # GH 6178
+                if np.isinf(fill):
+                    np.putmask(result,signs<0 & mask & ~nans,-fill)
+
                 result = result.reshape(shape)
 
     return result
diff --git a/pandas/core/ops.py b/pandas/core/ops.py
--- a/pandas/core/ops.py
+++ b/pandas/core/ops.py
@@ -454,7 +454,7 @@ def na_op(x, y):
 
             result, changed = com._maybe_upcast_putmask(result, -mask, pa.NA)
 
-        result = com._fill_zeros(result, y, fill_zeros)
+        result = com._fill_zeros(result, x, y, name, fill_zeros)
         return result
 
     def wrapper(left, right, name=name):
@@ -749,7 +749,7 @@ def na_op(x, y):
             result, changed = com._maybe_upcast_putmask(result, -mask, np.nan)
             result = result.reshape(x.shape)
 
-        result = com._fill_zeros(result, y, fill_zeros)
+        result = com._fill_zeros(result, x, y, name, fill_zeros)
 
         return result
 
@@ -913,7 +913,7 @@ def na_op(x, y):
             result[mask] = op(x[mask], y)
             result, changed = com._maybe_upcast_putmask(result, -mask, pa.NA)
 
-        result = com._fill_zeros(result, y, fill_zeros)
+        result = com._fill_zeros(result, x, y, name, fill_zeros)
         return result
 
     # work only for scalars
diff --git a/pandas/core/panel.py b/pandas/core/panel.py
--- a/pandas/core/panel.py
+++ b/pandas/core/panel.py
@@ -1396,7 +1396,7 @@ def na_op(x, y):
                 # handles discrepancy between numpy and numexpr on division/mod
                 # by 0 though, given that these are generally (always?)
                 # non-scalars, I'm not sure whether it's worth it at the moment
-                result = com._fill_zeros(result, y, fill_zeros)
+                result = com._fill_zeros(result, x, y, name, fill_zeros)
                 return result
 
             @Substitution(name)


Test patch:
diff --git a/pandas/tests/test_panel.py b/pandas/tests/test_panel.py
--- a/pandas/tests/test_panel.py
+++ b/pandas/tests/test_panel.py
@@ -2071,23 +2071,20 @@ def test_arith_flex_panel(self):
         else:
             aliases = {'div': 'truediv'}
         self.panel = self.panel.to_panel()
-        n = np.random.randint(-50, 50)
-        for op in ops:
-            try:
+
+        for n in [ np.random.randint(-50, -1), np.random.randint(1, 50), 0]:
+            for op in ops:
                 alias = aliases.get(op, op)
                 f = getattr(operator, alias)
-                result = getattr(self.panel, op)(n)
                 exp = f(self.panel, n)
+                result = getattr(self.panel, op)(n)
                 assert_panel_equal(result, exp, check_panel_type=True)
 
                 # rops
                 r_f = lambda x, y: f(y, x)
-                result = getattr(self.panel, 'r' + op)(n)
                 exp = r_f(self.panel, n)
+                result = getattr(self.panel, 'r' + op)(n)
                 assert_panel_equal(result, exp)
-            except:
-                print("Failing operation %r" % op)
-                raise
 
     def test_sort(self):
         def is_sorted(arr):
diff --git a/pandas/tests/test_series.py b/pandas/tests/test_series.py
--- a/pandas/tests/test_series.py
+++ b/pandas/tests/test_series.py
@@ -2212,6 +2212,12 @@ def test_div(self):
         assert_series_equal(result, p['first'].astype('float64'))
         self.assertFalse(np.array_equal(result, p['second'] / p['first']))
 
+        # inf signing
+        s = Series([np.nan,1.,-1.])
+        result = s / 0
+        expected = Series([np.nan,np.inf,-np.inf])
+        assert_series_equal(result, expected)
+
     def test_operators(self):
 
         def _check_op(series, other, op, pos_only=False):