Python Exercise

Research the arange function from the Numpy library and the list and map functions.  On the Python command line, code a procedure to convert an 8-bit binary string to a base-10 integer.  Hint: With arange, generate a Numpy array that contains the powers of 2 in their correct positions.  In other words, the array will be [7, 6, 5, 4, 3, 2, 1, 0]. Use list and map together to obtain an array or list of the integers 0 and 1 that can be used in vector computations.  For example, if the binary string representation is ‘00110101’, use list and map to obtain the list (or array) [0, 0, 1, 1, 0, 1, 0, 1].  Then, using vector multiplication and exponentiation, multiply that list by powers of 2 obtained from the position array ([7, 6, 5, …]).

 

Vector operations in Python are quite easy.  For instance, if [7, 6, 5, …] is a Numpy array, and [0, 0, 1, 1, 0, 1, 0, 1] is a list, then:

 

There are multiple correct approaches to solve this problem.

 

>>> b = '00110101'

>>> len(b)

8

>>> blist = list(b)

>>> blist

['0', '0', '1', '1', '0', '1', '0', '1']

>>> posn = [7,6,5,4,3,2,1,0]

>>> posn = np.arange(7,0,step=-1)

>>> posn

array([7, 6, 5, 4, 3, 2, 1])

>>> posn = np.arange(8,0,step=-1) - 1

>>> posn

array([7, 6, 5, 4, 3, 2, 1, 0])

>>> bb = blist == '1'

>>> bb

False

>>> blist0 = list(map(int, blist))

>>> blist0

[0, 0, 1, 1, 0, 1, 0, 1]

>>> blist0 * posn

array([0, 0, 5, 4, 0, 2, 0, 0])

>>> blist0 * 2**posn

array([ 0,  0, 32, 16,  0,  4,  0,  1])

>>> sum(blist0 * 2**posn)

53

>>>

 

Floating point numbers, or non-integers, as well as negative numbers, can be expressed in a variety of ways.  There are various standards that are used by microprocessor manufacturers to represent these non-integral values.  This topic is beyond the scope of the current discussion.  However, a short discussion on representing fractions is needed.  Just as bits (having values 0 or 1) are used for integers, bits to the right of the decimal point (i.e. the fractional part) represent fractional powers of 2.  For instance, 21 = 2, 20 = 1, and 2-1 = 1/21 = ½.  Similarly. 2-2 = 1/22 = 1/4, 2-3 = 1/23 = 1/8, 24 = 1/24 = 1/16, etc.  Consequently,

 

0.12 (0.1 in binary) = 2-1 = 1/21 = ½

0.012 = 2-2 = 1/22 = 1/4,

0.0012 = 2-3 = 1/23 = 1/8

0.00012 = 24 = 1/24 = 1/16, etc.

 

As was the case with integers, one can determine the base-10 representation of a fraction through sums of various powers of 2.  For example,

 

0.1012 = (1 x 2-1) + (0 x 2-2) + (1 x 2-3) = ½ + 0 + 1/8 = 5/8 = 0.625

0.00112 = (0 x 2-1) + (0 x 2-2) + (1 x 2-3) + (1 x 2-4) = 0 + 0 + 1/8 + 1/16 = 3/16 = 0.1875

 

The same procedure can be applied if the number has an integer part (i.e., mixed fractions).  For example,

 

11011.011012 = (1 x 24) + (1 x 23) + (0 x 22) + (1 x 21) + (1 x 20) + (0 x 2-1) + (1 x 2-2) + (1 x 2-3) + (0 x 2-4) + (0 x 2-5)

= 16 + 8 + 0 + 2 + 1 + 0 + ¼ + 1/8 + 0 + 1/32

= 27 + ¼ + 1/8 + 1/32

= 27 13/32

= 27.40625

 

The reader may have observed that although any integer can be expressed perfectly in binary, fractional numbers can only be perfectly represented if they are sums of negative powers of 2.  For example, the very common decimal number 0.110 (0.1 in decimal, base-10 format) does not have a perfect binary representation.  In a digital computer, 0.110 can only be approximated in binary (base-2) format.  One such approximation, with 9 binary decimal places, is 0.0001100112:

 

0.0001100112 = 2-4 + 2-5 + 2-8 + 2-9 = 1/16 + 1/32 + 1/256 + 1/512 = 0.09960937510 ≈ 0.110.

 

It is clear that most fractional numbers cannot be expressed perfectly in binary.  Very common fractions, like 1/3, 1/5, 1/20 (5%) etc. do not have a perfect binary representation.

 

For experimentation with mixed binary numbers, the Python function convert_mixed_binary_to_decimal is provided in the code distribution for this course.   Some examples, as well as checks implemented on the Python command line, are shown below.

 

>>> convert_mixed_binary_to_decimal('11011.0101011')

27.3359375

>>> ## Use an existing function to check the integral part.  Note that 8 bits are required for using this function.

>>> nint = convert_8bit_binary_to_decimal('00011011')

>>> nint

27

>>> ## Calculate the fractional part.

>>> nfrac = 1/4 + 1/16 + 1/64 + 1/128

>>> nfrac

0.3359375

>>> n = nint + nfrac

>>> n

27.3359375

>>> ## Final check....

>>> n == convert_mixed_binary_to_decimal('11011.0101011')

True

>>>

 

An additional, longer example follows.

 

>>> b = '111101010011.0111011100101'

>>> x = convert_mixed_binary_to_decimal(b)

>>> x

3923.4654541015625

>>> ## The integer part is longer than 8 bits, so the available conversion cannot be used.  However, the built-in Python function int can be employed.

>>> nint = int('111101010011', 2)

>>> nint

3923

>>> ## The fractional part will be calculated in a straightforward manner for clarity.

>>> ## Exponents (the powers) will be put into a Numpy array.

>>> powers = np.array([2, 3, 4, 6, 7, 8, 11, 13])

>>> ## Make the powers negative.

>>> powers = -powers

>>> powers

array([ -2,  -3,  -4,  -6,  -7,  -8, -11, -13])

>>> ## Sum the powers of 2.

>>> nfrac = sum(2.0 ** powers)

>>> nfrac

0.4654541015625

>>> n = nint + nfrac

>>> n

3923.4654541015625

>>> ## Final check....

>>> n == convert_mixed_binary_to_decimal(b)

True

 

Implementation Note:

 

In Python, the logical expressions used in the examples above can be defined to obtain the corresponding truth tables.  The not, and, and or operators are operators in the Python language.  The XOR operation is implemented with the ^ operator.

 

Example 1

 

>>> ## ((a AND b) OR (a XOR b)) NAND (NOT(a) NOR b)

>>> def expr1(a, b):

return not(((a and b) or (a ^ b)) and (not(not(a) or b)))

 

>>> for a in (False, True):

for b in (False, True):

print(expr1(a, b), " ", end="")

print()

 

 

True  True

False  True

 

 

Example 2

 

>>> ## NOT(NOT(a XOR (a AND B)) OR (a NOR (a AND (a XOR b))))

>>> def expr2(a, b):

res0 = not(a ^ (a and b))

res1 = not(a or (a and (a ^ b)))

return(not(res0 or res1))

 

>>> for a in (False, True):

for b in (False, True):

print(expr2(a, b), " ", end="")

print()

 

 

False  False

True  False

[Code Resources]

[Work Cited]

License

Icon for the Creative Commons Attribution-ShareAlike 4.0 International License

Contemporary Digital Humanities Copyright © 2022 by Mark P. Wachowiak is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License, except where otherwise noted.

Share This Book