@@ -812,15 +812,23 @@ def unique1d(values):
812812 return uniques
813813
814814
815- def _checked_add_with_arr (arr , b ):
815+ def _checked_add_with_arr (arr , b , arr_mask = None , b_mask = None ):
816816 """
817+ Perform array addition that checks for underflow and overflow.
818+
817819 Performs the addition of an int64 array and an int64 integer (or array)
818- but checks that they do not result in overflow first.
820+ but checks that they do not result in overflow first. For elements that
821+ are indicated to be NaN, whether or not there is overflow for that element
822+ is automatically ignored.
819823
820824 Parameters
821825 ----------
822826 arr : array addend.
823827 b : array or scalar addend.
828+ arr_mask : boolean array or None
829+ array indicating which elements to exclude from checking
830+ b_mask : boolean array or boolean or None
831+ array or scalar indicating which element(s) to exclude from checking
824832
825833 Returns
826834 -------
@@ -832,16 +840,40 @@ def _checked_add_with_arr(arr, b):
832840 ------
833841 OverflowError if any x + y exceeds the maximum or minimum int64 value.
834842 """
835- # For performance reasons, we broadcast 'b' to the new array 'b2'
836- # so that it has the same size as 'arr'.
837- if _np_version_under1p10 :
838- if lib .isscalar (b ):
839- b2 = np .empty (arr .shape )
840- b2 .fill (b )
843+ def _broadcast (arr_or_scalar , shape ):
844+ """
845+ Helper function to broadcast arrays / scalars to the desired shape.
846+
847+ This function is compatible with different versions of NumPy and is
848+ implemented for performance reasons.
849+ """
850+ if _np_version_under1p10 :
851+ if lib .isscalar (arr_or_scalar ):
852+ out = np .empty (shape )
853+ out .fill (arr_or_scalar )
854+ else :
855+ out = arr_or_scalar
841856 else :
842- b2 = b
857+ out = np .broadcast_to (arr_or_scalar , shape )
858+ return out
859+
860+ b2 = _broadcast (b , arr .shape )
861+ if b_mask is not None :
862+ b2_mask = _broadcast (b_mask , arr .shape )
863+ else :
864+ b2_mask = None
865+
866+ # For elements that are NaN, regardless of their value, we should
867+ # ignore whether they overflow or not when doing the checked add.
868+ if arr_mask is not None and b2_mask is not None :
869+ not_nan = np .logical_not (arr_mask | b2_mask )
870+ elif arr_mask is not None :
871+ not_nan = np .logical_not (arr_mask )
872+ elif b_mask is not None :
873+ not_nan = np .logical_not (b2_mask )
843874 else :
844- b2 = np .broadcast_to (b , arr .shape )
875+ not_nan = np .empty (arr .shape , dtype = bool )
876+ not_nan .fill (True )
845877
846878 # gh-14324: For each element in 'arr' and its corresponding element
847879 # in 'b2', we check the sign of the element in 'b2'. If it is positive,
@@ -854,12 +886,14 @@ def _checked_add_with_arr(arr, b):
854886 mask2 = b2 < 0
855887
856888 if not mask1 .any ():
857- to_raise = (np .iinfo (np .int64 ).min - b2 > arr ).any ()
889+ to_raise = (( np .iinfo (np .int64 ).min - b2 > arr ) & not_nan ).any ()
858890 elif not mask2 .any ():
859- to_raise = (np .iinfo (np .int64 ).max - b2 < arr ).any ()
891+ to_raise = (( np .iinfo (np .int64 ).max - b2 < arr ) & not_nan ).any ()
860892 else :
861- to_raise = ((np .iinfo (np .int64 ).max - b2 [mask1 ] < arr [mask1 ]).any () or
862- (np .iinfo (np .int64 ).min - b2 [mask2 ] > arr [mask2 ]).any ())
893+ to_raise = (((np .iinfo (np .int64 ).max -
894+ b2 [mask1 ] < arr [mask1 ]) & not_nan [mask1 ]).any () or
895+ ((np .iinfo (np .int64 ).min -
896+ b2 [mask2 ] > arr [mask2 ]) & not_nan [mask2 ]).any ())
863897
864898 if to_raise :
865899 raise OverflowError ("Overflow in int64 addition" )
0 commit comments