I have two numbers encoded in a reversed list of digits. First I made multiplication in "Peano" way:
#from summa import summa
#from predecessor import predecessor
#def multiply(m, n):
# def _(b):
# return [0] if is_zero(b) else summa(m, _(predecessor(b)))
# return [0] if is_zero(m) or is_zero(n) else summa(m, _(predecessor(n)))
but my intention is to find out, if carry method presented below is more efficient.
While the algo itself should work, I need some assistance, if the middle part of it could be optimized. At the moment it looks overly complex, but I haven't find a way to simplify it. Of course it could be an unavoidable effect of the way I have chosen to carry and pass parameters, but if someone could either confirm the case or do some optimization suggestions, I'd greatly appreciate it.
# encode int to binary list
def bn(n):
return list(reversed(list(map(lambda x: 1 if x == "1" else 0, "{0:b}".format(n)))))
def is_zero(n):
return not n[1:] and not n[0]
def is_one(n):
return not n[1:] and n[0]
# multiplication
def multiply2(a, b):
def _(c, d, f, g, e):
if not b and not c:
return g + (e if e[1] else e[:1])
if c:
# clumsy part is the formation of A and x
A = 0 if (0 if (1 if c[0] and d else 0) == (e[1] if e else 0) else 1) == (f[0] if f else 0) else 1
# x = [0, 0] or [1, 0] or [0, 1] or [1, 1]
x = [A, 1 if ((e[1] if e else 0) or (f[0] if f else 0)) and c[0] and d or \
((e[1] if e else 0) and (f[0] if f else 0)) and not c[0] and d else 0]
#print(x, c, d, e, f, g)
return _(c[1:], d, f[1:], (g + e[:1] if e else g), x)
return g[:1] + _(a, b.pop(0), g[1:] + e, [], [])
return [0] if is_zero(a) or is_zero(b) else \
b if is_one(a) else \
a if is_one(b) else _(a, b.pop(0), [], [], [])
# test cases
for i in range(101):
for j in range(101):
x, y = bn(i*j), multiply2(bn(i), bn(j))
if x != y:
print("prod %s * %s = %s:" % (i, j, (i*j)), x, "->", y)
Please note the comment: "clumsy part is the formation of A and x" which is due to required optimization.
The last double for loop iterates numbers from 0 to 100 and multiplies them, which is for checking that algo works correctly.
Note, that I can do only simple comparison, boolean checks and list cut/concat operations on the algo.
Addition
In the simple sample output:
print(multiply2(bn(10), bn(10)), bn(10*10))
both lists should be same.
Also
This algo is based on the schema presented below, althought the one below is using base ten numbers, but carrying logic is same in the right part of the spreadsheet:
Left part is the common multiplication shema learnt in the elementary schools and one really could to repeated additions as on my commented "Peano" example. But my intuition says multiply2
method is faster until we really want to go to the Fast Fourier transform algorithms.
bn(n)
could bebn(n): return list(bin(n))[2:]
. \$\endgroup\$