Pandas version checks

  • [X] I have checked that this issue has not already been reported.

  • [X] I have confirmed this bug exists on the latest version of pandas.

  • [ ] I have confirmed this bug exists on the main branch of pandas.

Reproducible Example

import pandas as pd
s = pd.Series([36], dtype='UInt8')
100 * s # This returns a series with one value: 16 (!!)
s.mul(100) # Also returns a wrong value

# But
7 * s # This returns the correct value

8 * s # This returns the wrong value (overflow)

100. * s # returns the correct value (due to casting I guess)

Issue Description

When multiplying a UInt8 series by a python integer, for which the result overflows the dtype range, the resulting values are wrong.

AFAICT this only happens with the UInt8 dtype (I tested UInt8, UInt16, UInt32 and UInt64). Other UInt dtypes are properly casted to the "next" dtype.

Anybody computing percentages on UInt8 dtypes will easily hit this issue.

This was introduced in the 2.1.0 Release.

Expected Behavior

I expect the series to be casted to UInt16 when the results overflow the UInt8 range and return the correct values.

Installed Versions

INSTALLED VERSIONS ------------------ commit : fd3f57170aa1af588ba877e8e28c158a20a4886d python : 3.11.6.final.0 python-bits : 64 OS : Linux OS-release : 5.15.153.1-microsoft-standard-WSL2 Version : #1 SMP Fri Mar 29 23:14:13 UTC 2024 machine : x86_64 processor : x86_64 byteorder : little LC_ALL : None LANG : C.UTF-8 LOCALE : en_US.UTF-8 pandas : 2.2.0 numpy : 1.26.4 pytz : 2024.1 dateutil : 2.9.0.post0 setuptools : 70.3.0 pip : 23.3.1 Cython : None pytest : 7.4.4 hypothesis : None sphinx : 7.3.7 blosc : None feather : None xlsxwriter : None lxml.etree : None html5lib : None pymysql : 1.4.6 psycopg2 : None jinja2 : None IPython : 8.26.0 pandas_datareader : None adbc-driver-postgresql: None adbc-driver-sqlite : None bs4 : 4.12.3 bottleneck : None dataframe-api-compat : None fastparquet : None fsspec : 2024.6.1 gcsfs : None matplotlib : 3.9.1 numba : None numexpr : None odfpy : None openpyxl : 3.1.5 pandas_gbq : None pyarrow : 16.1.0 pyreadstat : None python-calamine : None pyxlsb : None s3fs : 2024.6.1 scipy : None sqlalchemy : 2.0.31 tables : None tabulate : None xarray : None xlrd : None zstandard : None tzdata : 2024.1 qtpy : None pyqt5 : None

Comment From: simran2jain

take

Comment From: BobChuckyJoe

Hi, wouldn't 16 be the correct value returned for 100 * 36 mod 256 ?

Comment From: Timost

Hi,

yes, 16 is the value corresponding to the overflow, so in a sense it is correct.

However, AFAICT, other UInt dtypes do not behave this way and are casted to the "next bigger" dtype when computation results overflow.

I think the behavior should be coherent across the various UInt flavours.

Comment From: rhshadrach

I believe pandas will overflow if integer being multiplied can be stored in the given dtype, but otherwise will upcast.

s = pd.Series([36], dtype='Int16')
print((s * 1000).dtype, (s * 1000).iloc[0])
# Int16 -29536
print((s * 32767).dtype, (s * 32767).iloc[0])
# Int16 -36
print((s * 32768).dtype, (s * 32768).iloc[0])
# Int32 1179648

Comment From: jbrockmendel

Looks like UInt16 has the same modular-arithmetic behavior I'd expect. I agree with @rhshadrach this is a non-issue.