Binary Addition using a carry - python

Im trying to add two binary numbers without converting the two numbers, S and T, into a base 10,using recursion and I'm having difficulty incorporating the carry into the code. Also, I'm not exactly sure what to do if one binary number is longer than the other.
def addB(S,T):
'''adds binary number without converting to base 10'''
def addBhelper(S,T,carry):
if S=='' and T=='':
return ''
if S[-1] + T[-1]+carry==0:
return addBhelper(S[:-1],T[:-1],0) + str((carry+int(S[-1]) + int(T[-1]))% 2)
if S[-1] + T[-1]+carry==1:
return addBhelper(S[:-1],T[:-1],1) + str((carry+int(S[-1]) + int(T[-1])) % 2)
if S[-1] + T[-1]+carry==2:
return addBhelper(S[:-1],T[:-1],2) + str((carry+int(S[-1]) + int(T[-1])) % 2)
if S[-1] + T[-1]+carry==3:
return addBhelper(S[:-1],T[:-1],2) + str((carry+int(S[-1]) + int(T[-1])) % 2)
return addBhelper(S,T,0)
---- updated to fix code formatting

Here's a cleaner version that uses some Python syntactic sugar:
def add(a,b,c=0):
if a == '' and b == '':
return str(c)
a = a or '0'
b = b or '0'
n = int(a[-1]) + int(b[-1]) + c
return add(a[:-1],b[:-1],n//2) + str(n%2)
Use default value of carry c=0 to get rid of the inner function
a = a or '0' sets a to '0' if it's ''
You forgot to convert string to integer before adding them
n//2 get the carry

Let’s start with the first part, which is making sure the two strings are the same length. Since they're numbers, all you have to do is '0' pad the shorter number
max_len = max(len(S), len(T))
# the more simple to understand way
while len(S) < max_len: S = '0' + S
while len(T) < max_len: T = '0' + T
# or you can use this python trickery
S = ('0' * (max_len - len(S))) + S
T = ('0' * (max_len - len(T))) + T
For the carries, your carries should be as follows:
For sum = 0, carry = 0
For sum = 1, carry = 0
For sum = 2, carry = 1
For sum = 3, carry = 1
Hope that helps,

Related

What is the fastest way to sum two strings made up of only numbers but without converting each to an int beforehand?

If I am given two strings made up of only numbers 0-9, what is the fastest way to sum the two? Doing something like str(int(num1) + int(num2)) is not allowed and fails.
It mentions in a failed test that the max for an int() is 4300 characters:
ValueError: Exceeds the limit (4300) for integer string conversion: value has 2102288 digits; use sys.set_int_max_str_digits() to increase the limit
Each of the two strings of numbers can be 1,000,000+ characters/numbers long, be empty strings, have mismatched lengths, and/or have leading zeros.
The only way that I can think of is to add each top/bottom digit one at a time from right-to-left and carry the 1 over when necessary.
My version passes all of the tests but fails on long numbers.
def sum_strings(x, y):
if not x:
x = '0'
if not y:
y = '0'
x_len = len(x)
y_len = len(y)
if x_len > y_len:
y = y.rjust(x_len, '0')
elif y_len > x_len:
x = x.rjust(y_len, '0')
carry = 0
total = ''
for index in range(len(x) - 1, -1, -1):
new_sum = int(x[index]) + int(y[index]) + carry
if new_sum > 9:
new_sum -= 10
carry = 1
else:
carry = 0
total = f'{new_sum}{total}'
answer = f'{carry}{total}' if carry else total
return answer if len(answer) > 1 else answer.lstrip('0')
Times out:
Here are the example "easy" test cases.
#test.describe('Basic tests')
def test_examples():
#test.it('Example tests')
def basic_tests():
test.assert_equals(sum_strings("1", "1"), "2")
test.assert_equals(sum_strings("123", "456"), "579")
Is there any way to do it faster?
EDIT: Here is the updated/working version although now that I can see other submissions I think there are cleaner ways to do it than this:
def sum_strings(x, y):
if not x:
x = '0'
if not y:
y = '0'
x_len = len(x)
y_len = len(y)
if x_len > y_len:
y = y.rjust(x_len, '0')
elif y_len > x_len:
x = x.rjust(y_len, '0')
carry = 0
total = []
for index in range(len(x) - 1, -1, -1):
new_sum = int(x[index]) + int(y[index]) + carry
if new_sum > 9:
new_sum -= 10
carry = 1
else:
carry = 0
total.append(str(new_sum))
if carry:
total.append(str(carry))
total_str = ''.join(reversed(total))
return total_str[1:] if len(total_str) > 1 and total_str[0] == '0' else total_str
Create a list of digits in the order you generate them, then create the final string using ''.join(reversed(digits)).

how to write a function that recursively sum the digits

I need a function that takes variables and then computes these variables (example for x and y xy) and recursively finds the sum of points there is two left.
But,
The function needs to print all the calculation.
For an example
Function is going to print this,53
Sorry for my bad english and good luck with the question.
Not very beautiful, but does the job
def f(x, y):
tmp = x**y
sum = 0
while tmp >= 1:
sum = sum + tmp % 10
tmp = (tmp // 10)
return sum
This might do it for you.
Not the most pretty code either:
def func(x,y):
res1 = str(x**y)
to_print = "{0}^{1} = {2}".format(x,y,res1)
while len(res1) > 1:
to_print += " = " + res1[0]
res2 = int(res1[0])
for n in res1[1:]:
to_print += " + " + n
res2 += int(n)
to_print += " = " + str(res2)
res1 = str(res2)
print(to_print)
Basically I created a string from the value of x**y so it would be easy to iterate(res1 = str(x**y)).
to_print saves the final output and is used to concatenate all the values.
to_print = "{0}^{1} = {2} = {3}".format(x,y,res1, res1[0])
I used a format string, if you are unfamiliar with this check this.
res2 saves the sum of the digits:
res2 = int(res1[0])
for n in res1[1:]:
res2 += int(n)

Figure out where decimal point goes when dividing floats as integers

I'm wanting to make a script that can perform maths on large numbers while keeping the precision as high as required. I attempted ones ages ago and division was the worst part by far, so I thought I'd try start with it this time.
Basically, I'm using str inputs, as they obviously remain perfectly accurate, and I'd like to perform calculations on them as integers so that nothing is lost to floating point numbers. I'm doing that currently by removing the decimal point before the calculation, then trying to re-add it, but I can't figure out how.
With multiplication, you can figure out the decimal by adding how many numbers are left of the decimal point in both numbers. Unfortunately that method doesn't seem to work with division. I previously tried coding long division, but again it's an awkward one if there's floats involved.
Here's the current code I've got, with some of the non working parts removed:
from __future__ import division
def _divide(a, b, precision):
count = 0
while a and count < precision:
for num in str(int(a // b)):
yield int(num)
count += 1
a = a % b * 10
def divide(a, b, precision=100, round_int=True):
result = []
a = str(a)
b = str(b)
#Check for negative numbers
a_neg = a[0] == '-'
b_neg = b[0] == '-'
if a_neg and not b_neg or b_neg and not a_neg:
result.append('-')
#Process number strings
a_split = a.split('.')
b_split = b.split('.')
try:
a = abs(int(a_split[0] + a_split[1]))
except IndexError:
a = abs(int(a_split[0]))
try:
b = abs(int(b_split[0] + b_split[1]))
except IndexError:
b = abs(int(b_split[0]))
#Calculate number
result += list(_divide(a, b, precision=precision+round_int))
if not round_int:
return ''.join(map(str, result))
#Round last integer
last_int = int(result.pop(-1))
index = -1
if last_int >= 5:
try:
result[index] += 1
except TypeError:
index -= 1
result[index] += 1
#Lower any integers above 10
while True:
if result[index] == '.':
index -= 1
if result[index] > 9:
result[index] -= 10
if result[index-1] == '.':
index -= 1
result[index-1] += 1
else:
return ''.join(map(str, result)).rstrip('.')
index -= 1
a = '365.72'
b = '2247.7'
print divide(a, b, 9, False)
print float(a) / float(b)
I just drew up a quick hacky way which uses the inbuilt float division to figure out where the decimal is, but obviously it's not ideal as it'll fail after 1e300:
cheat_div = str(abs(float(a) / float(b)))
if 'e' in cheat_div:
num_decimals = int(cheat_div.split('e')[1])
if num_decimals > 1:
num_decimals += 1
else:
if cheat_div.startswith('0.'):
num_decimals = 2 + len(cheat_div[2:].lstrip('0')) - len(cheat_div)
else:
try:
num_decimals = cheat_div.index('.')
except ValueError:
num_decimals = 0
while not result[is_negative]:
del result[is_negative]
if num_decimals:
if num_decimals > 0:
result = result[:is_negative+num_decimals] + ['.'] + result[is_negative+num_decimals:]
else:
result = result[:is_negative] + ['0', '.'] + ['0'] * -num_decimals + result[is_negative:]

Efficient solution for adding Binary Strings

Problem: Given two binary strings, return their sum (also a binary string).
For example, add_binary_strings('11', '1') should return '100'.
Implementation 1:
def addBinary(a, b):
"""
:type a: str
:type b: str
:rtype: str
"""
a = a[::-1]
b = b[::-1]
carry = '0'
result = ''
# Pad the strings to make their size equal
if len(a) < len(b):
for i in range(len(a), len(b)):
a += '0'
elif len(a) > len(b):
for i in range(len(b), len(a)):
b += '0'
n = len(a)
carry = 0
s = ''
for i in range(n):
l, m, c = int(a[i]), int(b[i]), carry
s += str(l^m^c) # sum is XOR of three bits
carry = (l&m) | (m&c) | (c&l) # carry is pairwise AND of three bits
if carry == 1:
s += str(carry)
return s[::-1]
Implementation 2
def addBinary(self, a, b):
"""
:type a: str
:type b: str
:rtype: str
"""
a = a[::-1]
b = b[::-1]
m = min(len(a), len(b))
carry = '0'
result = ''
for i in range(m):
r, carry = add_digit(a[i], b[i], carry=carry)
result += r
larger, shorter = a, b
if len(a) < len(b):
larger, shorter = b, a
for i in range(len(shorter), len(larger)):
if carry != '0':
r, carry = add_digit(larger[i], carry)
result += r
else:
result += larger[i]
if carry != '0':
result += carry
return result[::-1]
def add_digit(digit1, digit2, carry=None):
if carry is None:
carry = '0'
d1, d2, c = int(digit1), int(digit2), int(carry)
s = d1 + d2 + c
return str(s%2), str(s//2)
According to an online judge, the performance for the first implementation is better in terms of time. However, I find the first implementation to be a bit too verbose because I always have to make both the strings of the same size.
What is the time complexity of creating a new string of length n? I would like to know what are the corresponding space and time complexities for these implementations and how can I improve on the code.
What are the tradeoffs between the implementations and when should I not use a particular one of them?
For example, I should use the 2nd implementation in favour of the 1st
when the size of input strings will differ considerably on the
general.
If problem is defined as:
Given two binary strings, return their sum (also a binary string).
For example, add_binary_strings('11', '1') should return '100'.
Then you just need to do:
def add_binary_strings(a, b):
return '{:b}'.format(int(a,2) + int(b,2))
print(add_binary_strings('11', '1'))
This solution should be faster than the one you found.
I would modify your solution to:
def addBinary(a, b):
max_len = max(len(a), len(b))
a = a.zfill(max_len)
b = b.zfill(max_len)
c = ''
reminder = 0
for i in range(max_len-1, -1, -1):
c = str((int(a[i]) + int(b[i]) + reminder) % 2) + c
reminder = 1 if int(a[i]) + int(b[i])+ reminder > 1 else 0
c = str(reminder) + c
return c
this would save some inversions compared yo your solutions, which would save a bit of time (ouch!). You can omit the last assignment to c if you do not want to increase the length of the output, though you may overflow!

Evenly intermix two lists of elements (load balance)

Let's say I have two strings made with only 1 character:
'aaaaaaa'
'bbb'
I'd like to find an algorithm to produce a combined string of:
'aabaabaaba'
The two are merged so that there is the fewest # of consecutive characters from either list (in this case that # is 2). The length of each string is arbitrary, and I'd like for it to be symmetrical. Bonus points for extending it to more than just 2 strings.
I am doing this in python, but the language doesn't matter. This is for a load balancing problem I'm working on.
You can use the elements alternatively and use a letter of the longer string if necessary. You can determine whether an additional letter is possible with integer arithmetics: A fraction tells you how many letters come between each letter pair. You accumulate this fraction and use letters from the longer array as long as that accumulated fraction is larger than ½:
def intertwine(a, b):
""" Return a combination of string with fewest number of
consecutive elements from one string
"""
if len(b) > len(a):
return intertwine(b, a)
if not b:
return a
a = list(a)
b = list(b)
num = len(a) - len(b)
denom = len(b)
acc = 0
res = []
while a or b:
acc += num
while acc >= denom / 2:
if a: res += a.pop(0)
acc -= num
if a: res += a.pop(0)
if b: res += b.pop(0)
return "".join(res)
print intertwine("aaabaaa", "bbb") # "aababbaaba"
print intertwine("aaaaaaa", "b") # "aaabaaaa"
print intertwine("aaaaaa", "b") # "aaabaaa"
print intertwine("aa", "bbbbbb") # "bbabbabb"
print intertwine("", "bbbbbb") # "bbbbbb"
print intertwine("", "") # ""
import itertools
def intermix(*containers):
mix = []
for c in sorted(containers, key=lambda c: len(c)):
if len(c) >= len(mix):
bigger, smaller = c, mix
else:
bigger, smaller = mix, c
ratio, remainder = divmod(len(bigger), len(smaller) + 1)
chunk_sizes = (ratio + (1 if i < remainder else 0) for i in range(len(smaller) + 1))
chunk_offsets = itertools.accumulate(chunk_sizes)
off_start = 0
new_mix = []
for i, off in enumerate(chunk_offsets):
new_mix.extend(bigger[off_start:off])
if i == len(smaller):
break
new_mix.append(smaller[i])
off_start = off
mix = new_mix
return mix

Categories

Resources