Skip to content

Commit f1e7ac5

Browse files
fix numpy warnings when int64 does not fit into float64
1 parent aaf1143 commit f1e7ac5

File tree

4 files changed

+49
-2
lines changed

4 files changed

+49
-2
lines changed

pandas/_libs/lib.pyx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ cdef:
116116
object oUINT64_MAX = <uint64_t>UINT64_MAX
117117

118118
float64_t NaN = <float64_t>np.nan
119+
# the maximum absolute integer value that a 64-bit IEEE floating point number can store is when all 52 bits of its significand/mantissa are 1
120+
# see: https://en.wikipedia.org/wiki/Double-precision_floating-point_format
121+
# related concept in JavaScript:
122+
# https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER
123+
float64_t F64_SAFE_INT64_MAX = <float64_t>(2**53 - 1)
119124

120125
# python-visible
121126
i8max = <int64_t>INT64_MAX
@@ -2868,6 +2873,9 @@ def maybe_convert_objects(ndarray[object] objects,
28682873
result = uints
28692874
else:
28702875
result = ints
2876+
elif (np.absolute(floats) > F64_SAFE_INT64_MAX).any():
2877+
# GH 58485
2878+
raise ValueError("integer values with non-nullable dtype too large to be represented by float64, specify an integer dtype explicitly")
28712879
else:
28722880
result = floats
28732881
elif seen.nan_:

pandas/core/dtypes/cast.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -960,7 +960,7 @@ def convert_dtypes(
960960
if len(arr) < len(input_array) and not is_nan_na():
961961
# In the presence of NaNs, we cannot convert to IntegerDtype
962962
pass
963-
elif (arr.astype(int) == arr).all():
963+
elif np.array_equal(arr, np.trunc(arr), equal_nan=True):
964964
inferred_dtype = target_int_dtype
965965
else:
966966
inferred_dtype = input_array.dtype
@@ -987,7 +987,7 @@ def convert_dtypes(
987987
if len(arr) < len(input_array) and not is_nan_na():
988988
# In the presence of NaNs, we can't convert to IntegerDtype
989989
inferred_dtype = inferred_float_dtype
990-
elif (arr.astype(int) == arr).all():
990+
elif np.array_equal(arr, np.trunc(arr)):
991991
inferred_dtype = pandas_dtype_func("Int64")
992992
else:
993993
inferred_dtype = inferred_float_dtype

pandas/tests/dtypes/test_inference.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1747,6 +1747,20 @@ def test_boolean_dtype(self, data, skipna, index_or_series_or_array):
17471747
inferred = lib.infer_dtype(val, skipna=skipna)
17481748
assert inferred == "boolean"
17491749

1750+
def test_large_non_nullable_integer_objects(self):
1751+
# GH 58485
1752+
arr = np.array(
1753+
[
1754+
-9223372036854775808,
1755+
4611686018427387904,
1756+
9223372036854775807,
1757+
None,
1758+
],
1759+
dtype="object",
1760+
)
1761+
with pytest.raises(ValueError, match="too large to be represented by float64"):
1762+
lib.maybe_convert_objects(arr)
1763+
17501764

17511765
class TestNumberScalar:
17521766
def test_is_number(self):

pandas/tests/frame/test_constructors.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2793,6 +2793,31 @@ def __new__(cls, input_array):
27932793
expected = DataFrame(np.eye(3))
27942794
tm.assert_frame_equal(df, expected)
27952795

2796+
def test_large_non_nullable_integer_objects(self):
2797+
# GH 58485
2798+
data = {
2799+
"a": [
2800+
-9223372036854775808,
2801+
4611686018427387904,
2802+
9223372036854775807,
2803+
None,
2804+
],
2805+
"b": [
2806+
-9223372036854775808,
2807+
4611686018427387904,
2808+
9223372036854775807,
2809+
None,
2810+
],
2811+
"c": [
2812+
-9223372036854775808,
2813+
4611686018427387904,
2814+
9223372036854775807,
2815+
None,
2816+
],
2817+
}
2818+
with pytest.raises(ValueError, match="too large to be represented by float64"):
2819+
pd.DataFrame(data)
2820+
27962821

27972822
class TestDataFrameConstructorIndexInference:
27982823
def test_frame_from_dict_of_series_overlapping_monthly_period_indexes(self):

0 commit comments

Comments
 (0)