1.2. Integers#
1.2.1. Imprementation of Integers#
Digital computers express everything as bit strings as discussed in the previous section. Encoding an integer in a bit string is simple. Just interpret the string as a binary number. Consider a bit string \(b_{N-1} \cdots b_2 b_1 b_0\). Then, the corresponding integer in the binary form is \(I = \sum_{k=0}^{N-1} 2^k b_k\). For example, bit string \(101\) corresponds to integer \(1\times 1+ 2 \times 0 + 4 \times 1 =5\). If \(\ell\) is the length of a bit string, we can express integers up to \(2^\ell\). For example, three bits can encode \(2^3=8\) integers, \(0,1,2,\cdots, 7\).
In principle, huge integers can be implemented as long as there is enough memory. In principle Python allows us to use any integers. When we use an integer, sufficient number of bits are automatically allocated to it.
This feature is rather unique to python and most of common computer languages such as C++ and Fortran use several fixed length of integers, known as int8
, int16
, int32
, and int64
where the numbers indicate the length of bit strings. Therefore, only integers in a limited range are available. Moreover, the type of variable must be declared in advance in these language. Python allocates an appropriate size automatically and increases it dynamically when needed. Python is far more flexible in handling integer numbers than other languages.
Although the python core does not have the size limitation, we still have to worry about it in scientific computation. Since Python lacks mathematical functions, it relies on third-party packages. Moreover, python is an interpreter programming language, its computing speed is rather slow and thus python core alone is not suitable for large scale computation and it again relies on third-party packages. For scientific computation we commonly use numpy
and scipy
packages which use C++ in backend. In other words, when we use routines in the numpy
package, routines written in C++ are called for faster computation. Hence, numpy
internally uses the same size of integers as C++. Integers prepared in the python core may not be compatible with integers used in numpy
. If so, numpy
attempts to convert the python integer to a numpy
integer. If python integer is too large for numpy
, then overflow error occurs. Therefore, we need to know the range of integers we can use with numpy
and scipy
.
Consider unsigned integer type uint8
stored in an 8-bit string. A binary string of 8 bits can express 256 (=\(2^8\)) integers, ranging from 0 to 255. Signed integer int8
uses one bit for sign, 0 for \(+\) and 1 for \(-\), and the remaining 7 bits for absolute value. Hence, a half of 256 is negative and the other half is positive. The resulting range is from -128 to +127. Notice that the upper limit is 127 instead of 128 because 0 is a part of \(+\) number in this encoding scheme.
Table Table 1.2 shows the range of other signed integer types. The default size of signed integer is 32 bit in most computer languages. However, 64-bit integer can be used for large scale calculation. Common hardware cannot handle integers larger than 64 bit. If more than 64 bit is needed, you must use a special numerical library.
dtype |
bits |
min |
max |
---|---|---|---|
int8 |
8 |
-128 |
+127 |
int16 |
16 |
-32768 |
+32767 |
int32 |
32 |
-2147483648 |
+2147483647 |
int64 |
64 |
-9223372036854775808 |
+9223372036854775807 |
You can ask numpy
what is the range of integer using iinfo
.
import numpy as np
print('max of int64 =',np.iinfo('int64').max)
print('min of int64 =',np.iinfo('int64').min)
max of int64 = 9223372036854775807
min of int64 = -9223372036854775808
In the following example code, x and y are the same integer 123. However, their type is different. x is python integer and y is numpy
integer int32
.
import numpy as np
# using integer type in python
x = 123
print('x =',x,' type=',type(x))
# using numpy integer
y = np.int32(123)
print('y =',y,' type=',type(y))
x = 123 type= <class 'int'>
y = 123 type= <class 'numpy.int32'>
Example 1.3.1: Huge integer: Exponential
Python can handle even \(2 \times 10^{100}\). However, it does not work in numpy
as integer. The error message indicates that Overflow error occurred.
x=2 * 10**100
print(x)
y=np.int64(x)
print(y)
20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
---------------------------------------------------------------------------
OverflowError Traceback (most recent call last)
Cell In[4], line 3
1 x=2 * 10**100
2 print(x)
----> 3 y=np.int64(x)
4 print(y)
OverflowError: Python int too large to convert to C long
Example 1.3.2 Huge integer: Factorial
Factorial \(N!\) grows quickly as \(N\) increases. The python core can’t calculate factorial. math
package understands python integer and thus can handle huge integers. Function math.factorial() returns integer in python integer type. Let us try 1000! Can you imagine how big it is? Numpy can’t deal with it.
import math
x=math.factorial(1000)
print(type(x),' This is NOT int64')
print('1000! =',x)
<class 'int'> This is NOT int64
1000! = 402387260077093773543702433923003985719374864210714632543799910429938512398629020592044208486969404800479988610197196058631666872994808558901323829669944590997424504087073759918823627727188732519779505950995276120874975462497043601418278094646496291056393887437886487337119181045825783647849977012476632889835955735432513185323958463075557409114262417474349347553428646576611667797396668820291207379143853719588249808126867838374559731746136085379534524221586593201928090878297308431392844403281231558611036976801357304216168747609675871348312025478589320767169132448426236131412508780208000261683151027341827977704784635868170164365024153691398281264810213092761244896359928705114964975419909342221566832572080821333186116811553615836546984046708975602900950537616475847728421889679646244945160765353408198901385442487984959953319101723355556602139450399736280750137837615307127761926849034352625200015888535147331611702103968175921510907788019393178114194545257223865541461062892187960223838971476088506276862967146674697562911234082439208160153780889893964518263243671616762179168909779911903754031274622289988005195444414282012187361745992642956581746628302955570299024324153181617210465832036786906117260158783520751516284225540265170483304226143974286933061690897968482590125458327168226458066526769958652682272807075781391858178889652208164348344825993266043367660176999612831860788386150279465955131156552036093988180612138558600301435694527224206344631797460594682573103790084024432438465657245014402821885252470935190620929023136493273497565513958720559654228749774011413346962715422845862377387538230483865688976461927383814900140767310446640259899490222221765904339901886018566526485061799702356193897017860040811889729918311021171229845901641921068884387121855646124960798722908519296819372388642614839657382291123125024186649353143970137428531926649875337218940694281434118520158014123344828015051399694290153483077644569099073152433278288269864602789864321139083506217095002597389863554277196742822248757586765752344220207573630569498825087968928162753848863396909959826280956121450994871701244516461260379029309120889086942028510640182154399457156805941872748998094254742173582401063677404595741785160829230135358081840096996372524230560855903700624271243416909004153690105933983835777939410970027753472000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
scipy
has factorial function. It says 1000! = inf, meaning it is infinity. It returns the result in type float64
instead of integer type, which we discuss in next section.
import scipy.special as ss
x=ss.factorial(1000)
print(type(x))
print('1000! =',x)
<class 'numpy.float64'>
1000! = inf
1.2.2. Arithmetic operations between integers#
Python core provides basic arithmetic operations between integers. The result is python integer except for division whose result is python float (float is discussed in the following section.)
Addition (+): Adds two operands.
Subtraction (-): Subtracts the second operand from the first.
Multiplication (*): Multiplies two operands.
Division (/): Divides the first operand by the second, always returning a float result.
Floor Division (//): Divides the first operand by the second and returns the integer part of the quotient (rounds down to the nearest whole number).
Modulo (%): Returns the remainder of the division of the first operand by the second.
Exponentiation (**): Raises the first operand to the power of the second operand.
Python adheres to the standard order of operations.
parentheses are evaluated first
followed by exponents,
then multiplication and division (from left to right),
finally addition and subtraction (from left to right).
Example 1.3.3 Floor and Modulo
print(' floor of 10/3 =',10//3)
print('modulo of 10/3 =',10%3)
floor of 10/3 = 3
modulo of 10/3 = 1
Last modified on 08/04/2025 by R. Kawai.