Adding strings (as representation for base 12 numbers) and integrers/ other strings in python

Viewed 306

I need to create a calculator that can add numbers in base 12 and with different limits at the differents diggits.

Base 12 sequence: [0,1,2,3,4,5,6,7,8,9,"A","B"]

The limits must be:

  • First digit: limit "B"
  • Second digit: limit 4

That means you would count like this:[1,2,3,4,5,6,7,8,9,A,B,10,11,...48,49,4A,4B]

but I don´t know how could I make it so that I can sum 2 numbers

I have the following code in python:

list1=[0,1,2,3,4,5,6,7,8,9,"A","B"]
list2=[0,1,2,3,4]
list3=[0,1,2,3,4,5,6,7,8,9,"A","B"]
list4=[0,1,2,3,4]


def calculadora (entrada1, operacion, entrada2):
    #parte de valor 1:
    digito1_1=str(list2[int(entrada1//12)])
    digito1_2=str(list1[int(entrada1%12)])
    valor1=float(digito1_1+digito1_2)
    #parte de valor 2
    digito2_1=str(list2[int(entrada2//12)])
    digito2_2=str(list1[int(entrada2%12)])
    valor2=float(digito2_1+digito2_2)
    if operacion==str("suma") or "+":
        return float(valor1+valor2)
entrada1 = float(input("inserte primer valor"))
operacion=str(input("inserte operación"))
entrada2 = float(input("inserte segundo valor"))
print (calculadora(entrada1,operacion,entrada2))

It works for numbers but wenn I want to sum numbers like 3B, it gives me a ValueError as it is coded as string.

Could someone help me or say me how could I do it to sum such numbers please?

3 Answers

The easiest way to convert a base-12 encoded string to int is via int(string, 12). The reverse is not quite as easy, because Python doesn't seem to have a built-in way to do that. You can use format specifiers for binary, octal, and hex, but not arbitrary bases.

You can get a reversed list of digits using divmod(), which does division with remainder.

def to_digits(x, base):
     while x > 0:
         x, rem = divmod(x, base)
         yield rem

But to round-trip, we want a string. Convert the int to a character (using a string as a lookup table), and join them into a string, then use a negatively-stepped slice to reverse it.

def to_base_12(num):
    return ''.join('0123456789AB'[d] for d in to_digits(num, 12))[::-1]

With a longer lookup table, you could generalize this into higher bases.

Strings are already sequences, but if you want to convert that back to a list, you can just call list() on it. The inverse is that ''.join() method you just saw.

Now that you can convert your base-12 representation to Python int objects and back, you can simply add them with +.

Here is slight variation on the excellent answer from gilch that handles negative numbers and zero.

def convert_to_string(num, base):
    '''
    Convert integer (num) to base less than base 37.
    '''
    alpha = string.digits + string.ascii_lowercase

    assert isinstance(num, int)
    assert isinstance(base, int)
    assert 1 < base <= len(alpha)
    if num == 0:
        return '0'

    def to_digits(num, base, alpha):
        '''
        Generator to convert digits in reverse order.
        '''
        while num > 0:
            num, rem = divmod(num, base)
            yield alpha[rem]

    sign = ''
    if num < 0:
        num, sign = -num, '-'
    return sign + ''.join(d for d in reversed(tuple(to_digits(num, base, alpha))))


def convert_from_string(num, base):
    '''
    Convert string in base X to integer.
    '''
    return int(str(num), base)


def test():
    '''
    Test conversions.
    '''
    assert convert_to_string(0, 2) == '0'
    assert convert_to_string(4, 2) == '100'
    assert convert_to_string(23, 12) == '1b'
    assert convert_to_string(-6, 2) == '-110'
    assert convert_from_string('1b', 12) == 23
    assert convert_from_string('-110', 2) == -6

You can add them directly if you convert the A and B to 11 and 12. Then as each number is now a list of digits one can add them the same way that an ALU does. See the section on addition of integers in any text on computer arithmetic.

def add(A, B):

    result = []
    carry = 0
    for a, b in reversed(zip(A,B)):
        carry, digit = divmod(a + b + carry, 12)
        result.append(digit)

    if carry:
        result.append(carry)

    result.reverse()
    return result


>>> add([4,3],[6,11])
[11, 2]
>>> add([5,3],[6,11])
[1, 0, 2]

The lists are MSD first. The double reversing is not needed if the lists were in LSD first.

Related