Maximum and minimum value of C types integers from Python
Question:
I’m looking for a way to get (using Python) the maximum and minimum values of C types integers (ie uint8
, int8
, uint16
, int16
, uint32
, int32
, uint64
, int64
…) from Python.
I was expecting to find this in ctypes
module
In [1]: import ctypes
In [2]: ctypes.c_uint8(256)
Out[2]: c_ubyte(0)
In [3]: ctypes.c_uint8(-1)
Out[3]: c_ubyte(255)
but I couldn’t find it.
Julia have great feature for this:
julia> typemax(UInt8)
0xff
julia> typemin(UInt8)
0x00
julia> typemin(Int8)
-128
julia> typemax(Int8)
127
I’m pretty sure Python have something quite similar.
Ideally I’m even looking for a way to ensure that a given Python integer (which is said to be unbounded) can be converted safely in a C type integer of a given size.
When number is not in expected interval, it should raise an exception.
Currently overflow doesn’t raise exception:
In [4]: ctypes.c_uint8(256)
Out[4]: c_ubyte(0)
I saw this SO post Maximum and Minimum values for ints but it’s a bit different as author is looking for min/max value of a Python integer… not a C integer (from Python)
I also noticed Detecting C types limits ("limits.h") in python? but, even if it’s quite related, it doesn’t really answer my question.
Answers:
According to: [Python.Docs]: Numeric Types – int, float, complex:
Integers have unlimited precision.
Translated to code:
>>> i = 10 ** 100
>>> i
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
>>> len(str(i))
101
>>> i.bit_length()
333
On the other hand, each C type has a fixed size (depending on platform / architecture), as clearly shown in [CPPReference]: Fundamental types.
Since [Python.Docs]: ctypes – A foreign function library for Python doesn’t mention anything about types limits (note that there is some stuff not documented there), let’s find them out manually.
code00.py:
#!/usr/bin/env python3
import sys
from ctypes import c_int8, c_uint8, c_byte, c_ubyte, c_int16, c_uint16,
c_int32, c_uint32, c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong,
c_int64, c_uint64,
sizeof
def limits(c_int_type):
signed = c_int_type(-1).value < c_int_type(0).value
bit_size = sizeof(c_int_type) * 8
signed_limit = 2 ** (bit_size - 1)
return (-signed_limit, signed_limit - 1) if signed else (0, 2 * signed_limit - 1)
def main(*argv):
test_types = (
c_int8,
c_uint8,
c_byte,
c_ubyte,
c_int16,
c_uint16,
c_int32,
c_uint32,
c_int,
c_uint,
c_long,
c_ulong,
c_longlong,
c_ulonglong,
c_int64,
c_uint64,
)
for test_type in test_types:
print("{:s} limits: ({:d}, {:d})".format(test_type.__name__, *limits(test_type)))
if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}n".format(" ".join(elem.strip() for elem in sys.version.split("n")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("nDone.")
sys.exit(rc)
Notes:
-
Code relies on the fact that for a certain integral type, its interval (and limits are interval’s endpoints) is:
-
signed (2‘s complement): [-(2 bit_size – 1), 2 bit_size – 1 – 1]
-
unsigned: [0, 2 bit_size – 1]
-
To check the a type’s signum, use -1 (which will automatically be converted to the upper limit (due to wrap around arithmetic) by unsigned types)
-
There are lots of duplicates the output (below), because some types are simply "aliases" to others
-
The rest of your task (creating a function that compares a Python int to the CTypes type limits, and raises an exception if it isn’t) is trivial, so I didn’t implement it
-
This is for demonstrating purpose only, so I didn’t do any argument check
Output:
-
Win:
-
Python pc064 (064bit):
[cfati@CFATI-5510-0:e:WorkDevStackOverflowq052475749]> "e:WorkDevVEnvspy_pc064_03.09_test0Scriptspython.exe" ./code00.py
Python 3.9.9 (tags/v3.9.9:ccb0e6a, Nov 15 2021, 18:08:50) [MSC v.1929 64 bit (AMD64)] 064bit on win32
c_byte limits: (-128, 127)
c_ubyte limits: (0, 255)
c_byte limits: (-128, 127)
c_ubyte limits: (0, 255)
c_short limits: (-32768, 32767)
c_ushort limits: (0, 65535)
c_long limits: (-2147483648, 2147483647)
c_ulong limits: (0, 4294967295)
c_long limits: (-2147483648, 2147483647)
c_ulong limits: (0, 4294967295)
c_long limits: (-2147483648, 2147483647)
c_ulong limits: (0, 4294967295)
c_longlong limits: (-9223372036854775808, 9223372036854775807)
c_ulonglong limits: (0, 18446744073709551615)
c_longlong limits: (-9223372036854775808, 9223372036854775807)
c_ulonglong limits: (0, 18446744073709551615)
Done.
-
Python pc032 (032bit):
[cfati@CFATI-5510-0:e:WorkDevStackOverflowq052475749]> "e:WorkDevVEnvspy_pc032_03.10_test0Scriptspython.exe" ./code00.py
Python 3.10.1 (tags/v3.10.1:2cd268a, Dec 6 2021, 18:54:59) [MSC v.1929 32 bit (Intel)] 032bit on win32
c_byte limits: (-128, 127)
c_ubyte limits: (0, 255)
c_byte limits: (-128, 127)
c_ubyte limits: (0, 255)
c_short limits: (-32768, 32767)
c_ushort limits: (0, 65535)
c_long limits: (-2147483648, 2147483647)
c_ulong limits: (0, 4294967295)
c_long limits: (-2147483648, 2147483647)
c_ulong limits: (0, 4294967295)
c_long limits: (-2147483648, 2147483647)
c_ulong limits: (0, 4294967295)
c_longlong limits: (-9223372036854775808, 9223372036854775807)
c_ulonglong limits: (0, 18446744073709551615)
c_longlong limits: (-9223372036854775808, 9223372036854775807)
c_ulonglong limits: (0, 18446744073709551615)
Done.
-
Nix (Linux – WSL2) – Python pc064:
(qaic-env) [cfati@cfati-5510-0:/mnt/e/Work/Dev/StackOverflow/q052475749]> python ./code00.py
Python 3.8.10 (default, Mar 15 2022, 12:22:08) [GCC 9.4.0] 064bit on linux
c_byte limits: (-128, 127)
c_ubyte limits: (0, 255)
c_byte limits: (-128, 127)
c_ubyte limits: (0, 255)
c_short limits: (-32768, 32767)
c_ushort limits: (0, 65535)
c_int limits: (-2147483648, 2147483647)
c_uint limits: (0, 4294967295)
c_int limits: (-2147483648, 2147483647)
c_uint limits: (0, 4294967295)
c_long limits: (-9223372036854775808, 9223372036854775807)
c_ulong limits: (0, 18446744073709551615)
c_long limits: (-9223372036854775808, 9223372036854775807)
c_ulong limits: (0, 18446744073709551615)
c_long limits: (-9223372036854775808, 9223372036854775807)
c_ulong limits: (0, 18446744073709551615)
Done.
Notes (more or less related):
-
Many people encounter problems when calling functions via CTypes. Mentioning [SO]: C function called from Python via ctypes returns incorrect value (@CristiFati’s answer) just in case
-
-
I’m looking for a way to get (using Python) the maximum and minimum values of C types integers (ie uint8
, int8
, uint16
, int16
, uint32
, int32
, uint64
, int64
…) from Python.
I was expecting to find this in ctypes
module
In [1]: import ctypes
In [2]: ctypes.c_uint8(256)
Out[2]: c_ubyte(0)
In [3]: ctypes.c_uint8(-1)
Out[3]: c_ubyte(255)
but I couldn’t find it.
Julia have great feature for this:
julia> typemax(UInt8)
0xff
julia> typemin(UInt8)
0x00
julia> typemin(Int8)
-128
julia> typemax(Int8)
127
I’m pretty sure Python have something quite similar.
Ideally I’m even looking for a way to ensure that a given Python integer (which is said to be unbounded) can be converted safely in a C type integer of a given size.
When number is not in expected interval, it should raise an exception.
Currently overflow doesn’t raise exception:
In [4]: ctypes.c_uint8(256)
Out[4]: c_ubyte(0)
I saw this SO post Maximum and Minimum values for ints but it’s a bit different as author is looking for min/max value of a Python integer… not a C integer (from Python)
I also noticed Detecting C types limits ("limits.h") in python? but, even if it’s quite related, it doesn’t really answer my question.
According to: [Python.Docs]: Numeric Types – int, float, complex:
Integers have unlimited precision.
Translated to code:
>>> i = 10 ** 100 >>> i 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 >>> len(str(i)) 101 >>> i.bit_length() 333
On the other hand, each C type has a fixed size (depending on platform / architecture), as clearly shown in [CPPReference]: Fundamental types.
Since [Python.Docs]: ctypes – A foreign function library for Python doesn’t mention anything about types limits (note that there is some stuff not documented there), let’s find them out manually.
code00.py:
#!/usr/bin/env python3
import sys
from ctypes import c_int8, c_uint8, c_byte, c_ubyte, c_int16, c_uint16,
c_int32, c_uint32, c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong,
c_int64, c_uint64,
sizeof
def limits(c_int_type):
signed = c_int_type(-1).value < c_int_type(0).value
bit_size = sizeof(c_int_type) * 8
signed_limit = 2 ** (bit_size - 1)
return (-signed_limit, signed_limit - 1) if signed else (0, 2 * signed_limit - 1)
def main(*argv):
test_types = (
c_int8,
c_uint8,
c_byte,
c_ubyte,
c_int16,
c_uint16,
c_int32,
c_uint32,
c_int,
c_uint,
c_long,
c_ulong,
c_longlong,
c_ulonglong,
c_int64,
c_uint64,
)
for test_type in test_types:
print("{:s} limits: ({:d}, {:d})".format(test_type.__name__, *limits(test_type)))
if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}n".format(" ".join(elem.strip() for elem in sys.version.split("n")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("nDone.")
sys.exit(rc)
Notes:
-
Code relies on the fact that for a certain integral type, its interval (and limits are interval’s endpoints) is:
-
signed (2‘s complement): [-(2 bit_size – 1), 2 bit_size – 1 – 1]
-
unsigned: [0, 2 bit_size – 1]
-
-
To check the a type’s signum, use -1 (which will automatically be converted to the upper limit (due to wrap around arithmetic) by unsigned types)
-
There are lots of duplicates the output (below), because some types are simply "aliases" to others
-
The rest of your task (creating a function that compares a Python int to the CTypes type limits, and raises an exception if it isn’t) is trivial, so I didn’t implement it
-
This is for demonstrating purpose only, so I didn’t do any argument check
Output:
-
Win:
-
Python pc064 (064bit):
[cfati@CFATI-5510-0:e:WorkDevStackOverflowq052475749]> "e:WorkDevVEnvspy_pc064_03.09_test0Scriptspython.exe" ./code00.py Python 3.9.9 (tags/v3.9.9:ccb0e6a, Nov 15 2021, 18:08:50) [MSC v.1929 64 bit (AMD64)] 064bit on win32 c_byte limits: (-128, 127) c_ubyte limits: (0, 255) c_byte limits: (-128, 127) c_ubyte limits: (0, 255) c_short limits: (-32768, 32767) c_ushort limits: (0, 65535) c_long limits: (-2147483648, 2147483647) c_ulong limits: (0, 4294967295) c_long limits: (-2147483648, 2147483647) c_ulong limits: (0, 4294967295) c_long limits: (-2147483648, 2147483647) c_ulong limits: (0, 4294967295) c_longlong limits: (-9223372036854775808, 9223372036854775807) c_ulonglong limits: (0, 18446744073709551615) c_longlong limits: (-9223372036854775808, 9223372036854775807) c_ulonglong limits: (0, 18446744073709551615) Done.
-
Python pc032 (032bit):
[cfati@CFATI-5510-0:e:WorkDevStackOverflowq052475749]> "e:WorkDevVEnvspy_pc032_03.10_test0Scriptspython.exe" ./code00.py Python 3.10.1 (tags/v3.10.1:2cd268a, Dec 6 2021, 18:54:59) [MSC v.1929 32 bit (Intel)] 032bit on win32 c_byte limits: (-128, 127) c_ubyte limits: (0, 255) c_byte limits: (-128, 127) c_ubyte limits: (0, 255) c_short limits: (-32768, 32767) c_ushort limits: (0, 65535) c_long limits: (-2147483648, 2147483647) c_ulong limits: (0, 4294967295) c_long limits: (-2147483648, 2147483647) c_ulong limits: (0, 4294967295) c_long limits: (-2147483648, 2147483647) c_ulong limits: (0, 4294967295) c_longlong limits: (-9223372036854775808, 9223372036854775807) c_ulonglong limits: (0, 18446744073709551615) c_longlong limits: (-9223372036854775808, 9223372036854775807) c_ulonglong limits: (0, 18446744073709551615) Done.
-
-
Nix (Linux – WSL2) – Python pc064:
(qaic-env) [cfati@cfati-5510-0:/mnt/e/Work/Dev/StackOverflow/q052475749]> python ./code00.py Python 3.8.10 (default, Mar 15 2022, 12:22:08) [GCC 9.4.0] 064bit on linux c_byte limits: (-128, 127) c_ubyte limits: (0, 255) c_byte limits: (-128, 127) c_ubyte limits: (0, 255) c_short limits: (-32768, 32767) c_ushort limits: (0, 65535) c_int limits: (-2147483648, 2147483647) c_uint limits: (0, 4294967295) c_int limits: (-2147483648, 2147483647) c_uint limits: (0, 4294967295) c_long limits: (-9223372036854775808, 9223372036854775807) c_ulong limits: (0, 18446744073709551615) c_long limits: (-9223372036854775808, 9223372036854775807) c_ulong limits: (0, 18446744073709551615) c_long limits: (-9223372036854775808, 9223372036854775807) c_ulong limits: (0, 18446744073709551615) Done.
Notes (more or less related):
-
Many people encounter problems when calling functions via CTypes. Mentioning [SO]: C function called from Python via ctypes returns incorrect value (@CristiFati’s answer) just in case