a bases converter


7 posts
by antiloquax » Wed Oct 31, 2012 10:23 pm
I have re-written my python program to convert numbers from one base to another.
I was very pleased to learn the "enumerate()" function - thanks Blackjack for this!

I have now used this in my "to-denary" function and I think it is a lot better that my previous version.
I know this program could really do with some checking of input /error handling, but I am quite pleased with how it works so far ...
Code: Select all
# bases.py - converts a base to another base.
import math

def to_denary(n, b, D):
    """Converts to denary."""
    denary = 0
    for i in enumerate(reversed(n)):
        temp = D.index(i[1])
        denary += temp * math.pow(b, i[0])
    return denary

def to_base(n, b, D):
    """Converts n to base b."""
    result = ""
    while n != 0:
        temp = int(n % b)
        n //= b
        result = D[temp] + result
    return result

def main():
    DIGITS = "0123456789ABCDEF"
    print("**** Base conversion ***")
    base_a = input("Base of input:" )
    while base_a != "":
        base_a = int(base_a)
        base_b = int(input("Base for output: "))
        num = input("Number: ")
        ans = to_base((to_denary(num, base_a, DIGITS)), base_b, DIGITS)
        print("The base", base_a, "number", num, "in base", base_b, "is", ans)
        base_a = input("Base of input:" )
       
# call main
main()                 


At some point I want to make a GUI version.
Here's a sample run:
bases.png
bases.png (34.23 KiB) Viewed 453 times
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
by antiloquax » Thu Nov 01, 2012 8:28 am
I've realised that my enumerate would be nicer like this;
Code: Select all
def to_denary(n, b, D):
    """Converts to denary."""
    denary = 0
    for (i, digit)  in enumerate(reversed(n)):
        temp = D.index(digit)
        denary += temp * math.pow(b, i)
    return denary


:geek:
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
by BlackJack » Fri Nov 02, 2012 1:50 pm
@antiloquax: The name `to_denary()` is misleading. The function converts a string into an integer. A number itself does not have a base at all, it is only representations of a number as a string that have a base. There is nothing ten-based about an `int`. If at all one could say it is base two as most likely that is what the internal representation in memory is based on. Although it does not have to be — it is an implementation detail.

`math.pow()` operates on `float`\s, so the arguments are converted to `float` and the result is also a `float`. That is unnecessary here and with really big inputs `denary` might get to big for a `float` and the result becomes inexact.

There is a `pow()` function in the builtin namespace which operates on arbitrarily large integers. But I would simply use the power operator ``**`` unless the third argument of the builtin `pow()` is needed.

As that power value might become quite large for inputs with many digits an alternative algorithm which just needs one multiplication and one addition per loop iteration could be used:
Code: Select all
def to_int(digits, base, allowed_digits):
    result = 0
    for digit in digits:
        result = (result * base) + allowed_digits.index(digit)
    return result

The function lacks some error checking. And the more simple way would be to use the builtin `int()` function which takes an optional base as second argument. Bases up to 36 are possible.

`to_base()` could make use of the `divmod()` function.

Building strings by repeatedly concatenating parts is potentially inefficient because strings are immutable. A more idiomatic approach would be collecting the substrings in a list and joining them at the end.

The function also has a problem with converting the input value 0. Currently it returns an empty string instead of '0'.
Code: Select all
def to_base(number, base, allowed_digits):
    result = list()
    while number:
        number, index = divmod(number, base)
        result.append(allowed_digits[index])
    return ''.join(reversed(result)) if result else allowed_digits[0]
Code: Select all
while not self.asleep():
    sheep += 1
Posts: 288
Joined: Sat Aug 04, 2012 8:28 am
by antiloquax » Fri Nov 02, 2012 2:07 pm
Thanks BlackJack, I'll take another look and do some re-writing!
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
by joan » Fri Nov 02, 2012 2:16 pm
antiloquax wrote:I have re-written my python program to convert numbers from one base to another...

Well done!

I'm a bit old now but not so old that I don't remember the enjoyment I got from writing my own code to convert between bases.
User avatar
Posts: 4141
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK
by antiloquax » Fri Nov 02, 2012 3:21 pm
Thanks Joan. I mainly started working on this as a result of trying to explain bases to my GCSE computing group and describing to them how to do the conversions.
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am
by antiloquax » Sun Nov 04, 2012 3:56 pm
@BlackJack. I was not aware of divmod() or "**". Those two things certainly helped me to improve my code.
:D
Posts: 406
Joined: Sun Nov 20, 2011 11:37 am