4
\$\begingroup\$

I coded this program as a challenge for /r/dailyprogrammer. Basically this program can convert any number from any base to another base including negative bases as long as the input is coherent. Did I follow the Python 3 standard or commit any obvious mistakes? I am also wondering if I can efficiently filter out nonsensical input without making explicit cases for each one?

For example, if you input

-15-10

...that's nonsense because you can't have a negative number if you're in a negative base, if I understand correctly.

The program is run by giving it 3 inputs:

  1. The number
  2. The base the number you just inputted is in
  3. The base you'd like your output to be in

import sys

def convertToBase10(n, base):
    number = []
    negative = False

    # If n is a negative number (it's a string at this moment of the code)..
    # then replace the minus sign with a blank character to correctly convert string to int...
    # so the algorithm can continue.
    if n[0] == '-':
        n = n.replace('-', '')
        negative = True

    for i in n:
        number.append(int(i))

    number = number[::-1]
    if negative:
        for i in range(len(number)):
            number[i] = number[i] * -1
            number[i] = number[i] * (base ** i)
    else:
        for i in range(len(number)):
            number[i] = number[i] * (base ** i)

    return sum(number)

def convertToAnyBase(n, base):
    a = 0
    i = 0

    # Special case: If n is less than zero and base is greater than zero...
    #               then we have to take the absolute value of n before dividing it...
    #               using the // operator. Reason is because taking e.g. math.floor(-2.5)...
    #               returns -3.0 which is one off the actual value (we actually want -2 in this example).
    #               After we get the correct n, we can now negate it.
    if n < 0 and base > 0:
        while n < 0:
            remainder = n % base
            n = abs(n)
            n //= base
            n = -n

            # If the base is negative, remainder will be a negative number.
            # Add the absolute value of the base to the remainder and add one to n.
            # https://en.wikipedia.org/wiki/Negative_base#Calculation
            if remainder < 0:
                remainder += abs(base)
                n += 1

            a += remainder * (10 ** i)
            i += 1

        return -a

    while n != 0:
        remainder = n % base
        n //= base

        # If the base is negative, remainder will be a negative number.
        # Add the absolute value of the base to the remainder and add one to n.
        # https://en.wikipedia.org/wiki/Negative_base#Calculation
        if remainder < 0:
            remainder += abs(base)
            n += 1

        a += remainder * (10 ** i)
        i += 1
    return a 

def main():
    x = sys.argv[1]
    baseIn = int(sys.argv[2])
    baseOut = int(sys.argv[3])

    if baseIn == 0 or baseOut == 0:
        print("Cannot have bases of 0. Exiting...")
        raise SystemExit

    print("You entered " + x + " in base " + str(baseIn) + ".")

    n = convertToBase10(x, baseIn)

    if baseOut == 1:
        ones = str(1) * n
        print("Your number in base " + str(baseOut) + " is " + str(ones) + ".")
    elif baseOut == -1:
        ones = str(1) * n
        print("Your number in base " + str(baseOut) + " is " + str('-' + ones) + ".")
    else:
        # If both bases are ten then we have already calculated its value.
        if abs(baseIn) == 10 and abs(baseOut) == 10:
            print("Your number in base " + str(baseOut) + " is " + str(n) + ".")
        else:
            print("Your number in base " + str(baseOut) + " is " + str(convertToAnyBase(n, baseOut)) + ".")

if __name__ == "__main__":
    main()
\$\endgroup\$
6
\$\begingroup\$

A couple of simplifications are possible that will make this code more Pythonic.


Instead of declaring an empty number = [] and then appending elements, use a list comprehension:

number = [int(i) for i in reversed(n)]

Notice that I used reversed(...) instead of number[::-1], which seems a bit more intuitive to me.


Instead of this:

if n[0] == '-':
    n = n.replace('-', '')

I'd find it more clear:

if n.startswith('-'):
    n = n[1:]

At this point it's also clear that n is not a good name. n is usually used as a number, but here it's a string. Maybe "string" or "numString" would be better.

number is also not a good name. Since it's a list, making the name plural would be more natural.


Instead of this:

        number[i] = number[i] * -1
        number[i] = number[i] * (base ** i)

You could write in a shorter, more natural way:

        number[i] *= base ** i * -1

Similar to the previous point, this can be shortened:

        n = abs(n)
        n //= base
        n = -n

To this:

        n = abs(n) // base * -1

Basically this program can convert any number from any base to another base including negative bases as long as the input is coherent.

For input arguments 255 10 16 it gives me:

You entered 255 in base 10.
Your number in base 16 is 165.

Normally it should be ff, or at least (15, 15) or something...

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.