27
27
28
28
from pandas .core .dtypes .common import is_float_dtype , is_integer_dtype , is_scalar
29
29
30
- from .roperator import rdivmod
30
+ from .roperator import rdivmod , rfloordiv , rmod
31
31
32
32
33
33
def fill_zeros (result , x , y , name , fill ):
@@ -85,7 +85,7 @@ def fill_zeros(result, x, y, name, fill):
85
85
return result
86
86
87
87
88
- def mask_zero_div_zero (x , y , result , copy = False ):
88
+ def mask_zero_div_zero (x , y , result ):
89
89
"""
90
90
Set results of 0 / 0 or 0 // 0 to np.nan, regardless of the dtypes
91
91
of the numerator or the denominator.
@@ -95,9 +95,6 @@ def mask_zero_div_zero(x, y, result, copy=False):
95
95
x : ndarray
96
96
y : ndarray
97
97
result : ndarray
98
- copy : bool (default False)
99
- Whether to always create a new array or try to fill in the existing
100
- array if possible.
101
98
102
99
Returns
103
100
-------
@@ -113,10 +110,19 @@ def mask_zero_div_zero(x, y, result, copy=False):
113
110
>>> mask_zero_div_zero(x, y, result)
114
111
array([ inf, nan, -inf])
115
112
"""
113
+ if not isinstance (result , np .ndarray ):
114
+ # FIXME: SparseArray would raise TypeError with np.putmask
115
+ return result
116
+
116
117
if is_scalar (y ):
117
118
y = np .array (y )
118
119
119
120
zmask = y == 0
121
+
122
+ if isinstance (zmask , bool ):
123
+ # FIXME: numpy did not evaluate pointwise, seen in docs build
124
+ return result
125
+
120
126
if zmask .any ():
121
127
shape = result .shape
122
128
@@ -125,12 +131,13 @@ def mask_zero_div_zero(x, y, result, copy=False):
125
131
zpos_mask = zmask & ~ zneg_mask
126
132
127
133
nan_mask = (zmask & (x == 0 )).ravel ()
128
- neginf_mask = ((zpos_mask & (x < 0 )) | (zneg_mask & (x > 0 ))).ravel ()
129
- posinf_mask = ((zpos_mask & (x > 0 )) | (zneg_mask & (x < 0 ))).ravel ()
134
+ with np .errstate (invalid = "ignore" ):
135
+ neginf_mask = ((zpos_mask & (x < 0 )) | (zneg_mask & (x > 0 ))).ravel ()
136
+ posinf_mask = ((zpos_mask & (x > 0 )) | (zneg_mask & (x < 0 ))).ravel ()
130
137
131
138
if nan_mask .any () or neginf_mask .any () or posinf_mask .any ():
132
139
# Fill negative/0 with -inf, positive/0 with +inf, 0/0 with NaN
133
- result = result .astype ("float64" , copy = copy ).ravel ()
140
+ result = result .astype ("float64" , copy = False ).ravel ()
134
141
135
142
np .putmask (result , nan_mask , np .nan )
136
143
np .putmask (result , posinf_mask , np .inf )
@@ -157,36 +164,45 @@ def dispatch_missing(op, left, right, result):
157
164
-------
158
165
result : ndarray
159
166
"""
160
- opstr = "__{opname}__" .format (opname = op .__name__ ).replace ("____" , "__" )
161
167
if op is operator .floordiv :
162
168
# Note: no need to do this for truediv; in py3 numpy behaves the way
163
169
# we want.
164
170
result = mask_zero_div_zero (left , right , result )
165
171
elif op is operator .mod :
166
- result = fill_zeros (result , left , right , opstr , np .nan )
172
+ result = fill_zeros (result , left , right , "__mod__" , np .nan )
167
173
elif op is divmod :
168
174
res0 = mask_zero_div_zero (left , right , result [0 ])
169
- res1 = fill_zeros (result [1 ], left , right , opstr , np .nan )
175
+ res1 = fill_zeros (result [1 ], left , right , "__divmod__" , np .nan )
170
176
result = (res0 , res1 )
171
177
return result
172
178
173
179
174
180
# FIXME: de-duplicate with dispatch_missing
175
- def dispatch_fill_zeros (op , left , right , result , fill_value ):
181
+ def dispatch_fill_zeros (op , left , right , result ):
176
182
"""
177
183
Call fill_zeros with the appropriate fill value depending on the operation,
178
184
with special logic for divmod and rdivmod.
179
185
"""
180
186
if op is divmod :
181
187
result = (
182
- fill_zeros ( result [ 0 ], left , right , "__floordiv__" , np . inf ),
188
+ mask_zero_div_zero ( left , right , result [ 0 ] ),
183
189
fill_zeros (result [1 ], left , right , "__mod__" , np .nan ),
184
190
)
185
191
elif op is rdivmod :
186
192
result = (
187
- fill_zeros ( result [ 0 ] , left , right , "__rfloordiv__" , np . inf ),
193
+ mask_zero_div_zero ( right , left , result [ 0 ] ),
188
194
fill_zeros (result [1 ], left , right , "__rmod__" , np .nan ),
189
195
)
190
- else :
191
- result = fill_zeros (result , left , right , op .__name__ , fill_value )
196
+ elif op is operator .floordiv :
197
+ # Note: no need to do this for truediv; in py3 numpy behaves the way
198
+ # we want.
199
+ result = mask_zero_div_zero (left , right , result )
200
+ elif op is op is rfloordiv :
201
+ # Note: no need to do this for rtruediv; in py3 numpy behaves the way
202
+ # we want.
203
+ result = mask_zero_div_zero (right , left , result )
204
+ elif op is operator .mod :
205
+ result = fill_zeros (result , left , right , "__mod__" , np .nan )
206
+ elif op is rmod :
207
+ result = fill_zeros (result , left , right , "__rmod__" , np .nan )
192
208
return result
0 commit comments