2024-04-06 16:48:27 -05:00
#!/usr/bin/env python3
2024-04-06 18:03:56 -05:00
from tabulate import tabulate
2024-04-11 00:03:50 -05:00
import matplotlib . pyplot as plt
2024-04-06 18:03:56 -05:00
2024-04-06 16:48:27 -05:00
with open ( ' input.txt ' ) as f :
input_string = f . read ( ) . split ( ' \n ' )
def twos_comp ( num , length ) :
if num == 0 :
return 0
2024-04-06 18:03:56 -05:00
return abs ( ( num ^ ( ( 1 << length ) - 1 ) ) + 1 )
2024-04-06 16:48:27 -05:00
2024-04-10 22:20:55 -05:00
def arithmatic_shiftr ( num , length , times ) :
2024-04-06 16:48:27 -05:00
for t in range ( times ) :
2024-04-10 22:20:55 -05:00
num = ( num >> 1 ) | ( ( 1 << length - 1 ) & num )
2024-04-06 16:48:27 -05:00
return num
2024-04-10 22:20:55 -05:00
def arithmatic_shiftl ( num , length ) :
if num & ( 1 << length - 1 ) :
return ( num << 1 ) | ( 1 << length - 1 )
else :
return ( num << 1 ) & ~ ( 1 << length - 1 )
2024-04-11 00:03:50 -05:00
def twoscomp_to_int ( num , length ) :
2024-04-06 16:48:27 -05:00
if num & ( 1 << length - 1 ) :
return ( - 1 * twos_comp ( num , length ) )
return num & ( 1 << length ) - 1
2024-04-06 18:03:56 -05:00
def debug ( results ) :
headers = [ ' multiplicand bin ' , ' multiplier bin ' , ' multiplicand dec ' , ' multiplier dec ' , ' expected bin ' , ' expected dec ' , ' booth if correct ' , ' booth mod if correct ' ]
table = [ ]
for [ multiplicand_bin , multiplier_bin , result_booth , result_booth_mod , length ] in results :
2024-04-11 00:03:50 -05:00
multiplicand = twoscomp_to_int ( multiplicand_bin , length )
multiplier = twoscomp_to_int ( multiplier_bin , length )
2024-04-06 18:03:56 -05:00
expected = multiplicand * multiplier
expected_bin = ( twos_comp ( expected , length * 2 ) , expected ) [ expected > 0 ]
success_b = [ bin ( result_booth ) , " PASS " ] [ result_booth == expected_bin ]
success_bm = [ bin ( result_booth_mod ) , " PASS " ] [ result_booth_mod == expected_bin ]
table . append ( [ bin ( multiplicand_bin ) , bin ( multiplier_bin ) , multiplicand , multiplier , bin ( expected_bin ) , expected , success_b , success_bm ] )
2024-04-06 20:32:45 -05:00
print ( " \n CHECKS: \n " , tabulate ( table , headers ) , " \n " )
2024-04-06 16:48:27 -05:00
def booth ( multiplier , multiplicand , length ) :
2024-04-11 00:03:50 -05:00
operations = 0
2024-04-06 16:48:27 -05:00
multiplicand_twos_comp = twos_comp ( multiplicand , length )
result = multiplier << 1 # extended bit
for i in range ( length ) :
op = result & 0b11
if op == 0b01 :
2024-04-11 00:03:50 -05:00
operations + = 1
2024-04-06 16:48:27 -05:00
result + = multiplicand << ( length + 1 )
if op == 0b10 :
2024-04-11 00:03:50 -05:00
operations + = 1
2024-04-06 16:48:27 -05:00
result + = multiplicand_twos_comp << ( length + 1 )
result & = ( 1 << ( length * 2 ) + 1 ) - 1 # get rid of any overflows
2024-04-10 22:20:55 -05:00
result = arithmatic_shiftr ( result , ( length * 2 ) + 1 , 1 )
2024-04-06 16:48:27 -05:00
result = result >> 1
2024-04-11 00:03:50 -05:00
return ( result , operations )
2024-04-06 16:48:27 -05:00
def booth_mod ( multiplier , multiplicand , length ) :
2024-04-11 00:03:50 -05:00
operations = 0
2024-04-10 22:20:55 -05:00
multiplicand | = ( ( 1 << length - 1 ) & multiplicand ) << 1 # extend multiplicand sign to prevent overflow when mult/sub by 2
multiplicand_twos_comp = twos_comp ( multiplicand , length + 1 )
2024-04-06 16:48:27 -05:00
result = multiplier << 1 # extended bit
2024-04-10 22:20:55 -05:00
for i in range ( int ( ( length ) / 2 ) ) :
2024-04-11 00:03:50 -05:00
op = result & 0b111
match op :
2024-04-06 16:48:27 -05:00
case 0b010 | 0b001 : # add
2024-04-11 00:03:50 -05:00
print ( " add " )
2024-04-06 16:48:27 -05:00
result + = multiplicand << ( length + 1 )
2024-04-11 00:03:50 -05:00
operations + = 1
2024-04-06 16:48:27 -05:00
case 0b011 : # add * 2
2024-04-11 00:03:50 -05:00
print ( " add * 2 " )
result + = arithmatic_shiftl ( multiplicand , length + 1 ) << ( length + 1 )
operations + = 1
2024-04-06 16:48:27 -05:00
case 0b100 : # sub * 2
2024-04-11 00:03:50 -05:00
print ( " sub * 2 " )
result + = arithmatic_shiftl ( multiplicand_twos_comp , length + 1 ) << ( length + 1 )
operations + = 1
2024-04-06 16:48:27 -05:00
case 0b101 | 0b110 : # sub
2024-04-11 00:03:50 -05:00
print ( " sub " )
2024-04-06 16:48:27 -05:00
result + = multiplicand_twos_comp << ( length + 1 )
2024-04-11 00:03:50 -05:00
operations + = 1
2024-04-10 22:20:55 -05:00
result & = ( 1 << ( ( length * 2 ) + 2 ) ) - 1 # get rid of any overflows
result = arithmatic_shiftr ( result , ( length * 2 ) + 2 , 2 )
2024-04-11 00:03:50 -05:00
# *barfs on your dog*
2024-04-10 22:20:55 -05:00
result = ( ( result | ( ( 1 << ( ( length * 2 ) + 2 ) ) >> 1 ) ) & ( ( 1 << ( ( length * 2 ) + 1 ) ) - 1 ) ) >> 1
2024-04-11 00:03:50 -05:00
return ( result , operations )
2024-04-06 16:48:27 -05:00
2024-04-06 18:03:56 -05:00
if __name__ == " __main__ " :
headers = [ ' multiplicand ' , ' multiplier ' , ' result (bin) ' , ' result (hex) ' ]
table = [ ]
2024-04-11 00:03:50 -05:00
lengths = [ ] # for matplotlib plot
ops_booth = [ ]
ops_mod_booth = [ ]
2024-04-06 18:03:56 -05:00
debug_results = [ ]
for operation in input_string :
if operation == ' ' or operation [ 0 ] == ' # ' :
continue
length = len ( operation . split ( " " ) [ 0 ] )
multiplicand = int ( operation . split ( " " ) [ 0 ] , 2 )
multiplier = int ( operation . split ( " " ) [ 1 ] , 2 )
result_booth = booth ( multiplier , multiplicand , length )
2024-04-06 23:10:38 -05:00
result_mod_booth = booth_mod ( multiplier , multiplicand , length )
2024-04-11 00:03:50 -05:00
# gather data for matplotlib
ops_booth . append ( result_booth [ 1 ] )
ops_mod_booth . append ( result_mod_booth [ 1 ] )
lengths . append ( length )
table . append ( [ bin ( multiplicand ) , bin ( multiplier ) , bin ( result_booth [ 0 ] ) , hex ( result_booth [ 0 ] ) ] )
debug_results . append ( [ multiplicand , multiplier , result_booth [ 0 ] , result_mod_booth [ 0 ] , length ] )
2024-04-06 18:03:56 -05:00
debug ( debug_results )
print ( tabulate ( table , headers ) )
2024-04-11 00:03:50 -05:00
# generate graph
plt . plot ( lengths , ops_booth , ' ^--m ' , label = ' booths algorithim ' )
plt . plot ( lengths , ops_mod_booth , ' v--c ' , label = ' modified booths algorithim ' )
plt . gca ( ) . set_xlabel ( " Length of Operands " )
plt . gca ( ) . set_ylabel ( " Number of Additions and Subtractions " )
plt . legend ( loc = ' upper left ' )
plt . show ( )
2024-04-06 16:48:27 -05:00