views:

151

answers:

5

I'm trying to make a program to convert a number in any base to another base of the user's choice. The code I have so far goes like this:

innitvar = float(raw_input("Please enter a number: "))
basevar = int(raw_input("Please enter the base that your number is in: "))
convertvar = int(raw_input("Please enter the base that you would like to convert to: "))

These are the data that I get from the user. The innitial number, its innitial base, and the base the user wants to convert to. As I understand it, I need to convert to base 10, and then to the desired base, specified by the user.

This is where I'm hitting a brick wall. I need to multiply the leftmost digit in the initial number by its innitial base, and then add the next digit to the right, and then repeat until I hit the rightmost digit. I understand how to do this on paper, but I have no idea how to put it into Python code. I'm not sure how I would multiply the first number, and then add the next, nor do I understand how to let the program know when to stop performing this operation.

I'm not asking to have the program written for me, but I am asking to be pointed in the right direction.

Thanks for your time

A: 

You need to write two functions. In Scheme (since I know Scheme much better than Python :-P), those two functions are called string->number and number->string, though of course you can name them whatever you like.

Each of those functions needs to take a base parameter to do the conversion in. You can make it default to 10, if you like.

Once you implement each of those successfully, the rest is a piece of cake.

Test cases for you:

assert str2num('1234', 10) == 1234
assert str2num('1234', 16) == 0x1234
assert num2str(1234, 10) == '1234'
assert num2str(1234, 16) == '4d2'
assert num2str(0x1234, 16) == '1234'
Chris Jester-Young
I'm sorry, but I'm -very- unskilled in Python. Could you explain what you mean by "In Scheme, those two functions are called string->number and number->string", as well as the code you typed?
Just a Student
So, you need to write two functions: in the test cases, I've named them `str2num` and `num2str`. The first one converts the given string to a number, using the given base. The second one converts the given number to its string representation in the given base.
Chris Jester-Young
To get you started, you have to know to distinguish strings (the bits enclosed in quotes, in my test cases) and numeric values (the numbers not enclosed in quotes). Your `str2num` and `num2str` functions have to convert one form to the other.
Chris Jester-Young
In Python, you can use `str('1234')` and `str(1234)` (for example) to tell you which is which.
Chris Jester-Young
I suppose what I'm trying to ask is "What is assert? How is it used?". I'm really not getting the code. I don't see any calculations or anything like that, which comes back to my biggest problem, how to take the left digit and multiply, then add the right, and continue to the end of the number.
Just a Student
`assert` is pseudocode here. It just means, "this expression needs to be true". In other words, `str2num('1234', 16)` needs to have the same value as `0x1234`. As for the calculations themselves, that's something you have to figure out for yourself---this is homework after all.
Chris Jester-Young
I just feel more confused now. The root of my problem is that I have no clue how to use individual digits in a number.
Just a Student
A: 

int() can convert strings from any base between 2 and 36. If you need a wider range than that then create a string containing the digits and use the index() method to get the value.

Ignacio Vazquez-Abrams
Surely, for a homework problem, you aren't allowed to use shortcuts like `int()`? ;-)
Chris Jester-Young
@Chris: Learning how to use the built-in facilities is an important part of learning the language.
Ignacio Vazquez-Abrams
Yes, if the aim of the course is learning the language. But if the aim is actually to understand the operation of base conversion, with the language as purely a vehicle for practising that understanding, then the course requirements will reflect that.
Chris Jester-Young
My professor discourages most shortcuts or unnecessary modules. He wants us to manually code in any calculations.
Just a Student
@Just a Student: `int()` is built-in to Python, no modules needed.
Chris Jester-Young
I thought the int() function converted a none integer into an integer. I'm not sure how this helps with changing one base to another.
Just a Student
The second argument is a radix that is used to convert from a string to an int. It defaults to 10, but takes anything from 2 to 36. `>>> int('34f', 16)` `847`
Ignacio Vazquez-Abrams
+3  A: 

I need to multiply the leftmost digit in the initial number by its innitial base, and then add the next digit to the right, and then repeat until I hit the rightmost digit.

So you need to get digits. In a list.

Hint 1: Use divmod() function to break a number into digits. Divide by 10 to get decimal digits.

Hint 2: While n > 0: you can use divmod() to get a quotient and a remainder. If you save the remainder in the list, and use the quotient as the new value of n your number gets smaller until what's left is zero and you're done.

Hint 3: Your digits arrive in right-to-left order. Use reverse to switch the order of the list of this bothers you. Or create the list by using insert(0,digit).

Now that you have the digits. In a list. You can iterate through the list.

Try the for statement on for size.

You might need to use a "multiple and add" loop. total = total * new_base + next_digit is the way the body of the loop often looks.

S.Lott
Your answer is good, and I'm upvoting it. However, I discourage the `insert(0, digit)` approach unless you're dealing with a linked list---with an array (which Python uses, IIRC), each `insert(0, digit)` is an O(n) operation. (The `reverse`-at-the-end approach is the best one, of course.)
Chris Jester-Young
What you described is the method to use after getting your innitial base to base 10, correct? I'm understanding this part, but I'm not sure how to access individual digits in a number to multiply and add in order to move from innitial base to base 10.
Just a Student
@Chris Jester-Young. I'll assume you're talking about numbers with kabillions of digits. For ordinary 20-30 digit numbers, your optimization may not amount to much.
S.Lott
"You might need to use a "multiple and add" loop. total = total * new_base + next_digit is the way the body of the loop often looks." This is where I'm lost. I don't know how to multiply the first digit, then add the next, then repeat to the end.
Just a Student
@Just a Student: You have the digits in a list. They're separate numbers. Print the list. Look at it. Use `for i in someList:` to iterate through the digits/numbers. Try some code. Print stuff. Write `for` loops. Try things. Experiment. Explore.
S.Lott
+1  A: 

This should be the first half of the answer to your problem. Can you figure out how to convert to a base?

# Create a symbol-to-value table.
SY2VA = {'0': 0,
         '1': 1,
         '2': 2,
         '3': 3,
         '4': 4,
         '5': 5,
         '6': 6,
         '7': 7,
         '8': 8,
         '9': 9,
         'A': 10,
         'B': 11,
         'C': 12,
         'D': 13,
         'E': 14,
         'F': 15,
         'G': 16,
         'H': 17,
         'I': 18,
         'J': 19,
         'K': 20,
         'L': 21,
         'M': 22,
         'N': 23,
         'O': 24,
         'P': 25,
         'Q': 26,
         'R': 27,
         'S': 28,
         'T': 29,
         'U': 30,
         'V': 31,
         'W': 32,
         'X': 33,
         'Y': 34,
         'Z': 35,
         'a': 36,
         'b': 37,
         'c': 38,
         'd': 39,
         'e': 40,
         'f': 41,
         'g': 42,
         'h': 43,
         'i': 44,
         'j': 45,
         'k': 46,
         'l': 47,
         'm': 48,
         'n': 49,
         'o': 50,
         'p': 51,
         'q': 52,
         'r': 53,
         's': 54,
         't': 55,
         'u': 56,
         'v': 57,
         'w': 58,
         'x': 59,
         'y': 60,
         'z': 61,
         '!': 62,
         '"': 63,
         '#': 64,
         '$': 65,
         '%': 66,
         '&': 67,
         "'": 68,
         '(': 69,
         ')': 70,
         '*': 71,
         '+': 72,
         ',': 73,
         '-': 74,
         '.': 75,
         '/': 76,
         ':': 77,
         ';': 78,
         '<': 79,
         '=': 80,
         '>': 81,
         '?': 82,
         '@': 83,
         '[': 84,
         '\\': 85,
         ']': 86,
         '^': 87,
         '_': 88,
         '`': 89,
         '{': 90,
         '|': 91,
         '}': 92,
         '~': 93}

# Take a string and base to convert to.
# Allocate space to store your number.
# For each character in your string:
#     Ensure character is in your table.
#     Find the value of your character.
#     Ensure value is within your base.
#     Self-multiply your number with the base.
#     Self-add your number with the digit's value.
# Return the number.

def str2int(string, base):
    integer = 0
    for character in string:
        assert character in SY2VA, 'Found unknown character!'
        value = SY2VA[character]
        assert value < base, 'Found digit outside base!'
        integer *= base
        integer += value
    return integer

Here is the second half of the solution. By using these two functions, converting bases is very easy to do.

# Create a value-to-symbol table.
VA2SY = dict(map(reversed, SY2VA.items()))

# Take a integer and base to convert to.
# Create an array to store the digits in.
# While the integer is not zero:
#     Divide the integer by the base to:
#         (1) Find the "last" digit in your number (value).
#         (2) Store remaining number not "chopped" (integer).
#     Save the digit in your storage array.
# Return your joined digits after putting them in the right order.

def int2str(integer, base):
    array = []
    while integer:
        integer, value = divmod(integer, base)
        array.append(VA2SY[value])
    return ''.join(reversed(array))

After putting it all together, you should end up with the program below. Please take time to figure it out!

innitvar = raw_input("Please enter a number: ")
basevar = int(raw_input("Please enter the base that your number is in: "))
convertvar = int(raw_input("Please enter the base that you would like to convert to: "))

# Create a symbol-to-value table.
SY2VA = {'0': 0,
         '1': 1,
         '2': 2,
         '3': 3,
         '4': 4,
         '5': 5,
         '6': 6,
         '7': 7,
         '8': 8,
         '9': 9,
         'A': 10,
         'B': 11,
         'C': 12,
         'D': 13,
         'E': 14,
         'F': 15,
         'G': 16,
         'H': 17,
         'I': 18,
         'J': 19,
         'K': 20,
         'L': 21,
         'M': 22,
         'N': 23,
         'O': 24,
         'P': 25,
         'Q': 26,
         'R': 27,
         'S': 28,
         'T': 29,
         'U': 30,
         'V': 31,
         'W': 32,
         'X': 33,
         'Y': 34,
         'Z': 35,
         'a': 36,
         'b': 37,
         'c': 38,
         'd': 39,
         'e': 40,
         'f': 41,
         'g': 42,
         'h': 43,
         'i': 44,
         'j': 45,
         'k': 46,
         'l': 47,
         'm': 48,
         'n': 49,
         'o': 50,
         'p': 51,
         'q': 52,
         'r': 53,
         's': 54,
         't': 55,
         'u': 56,
         'v': 57,
         'w': 58,
         'x': 59,
         'y': 60,
         'z': 61,
         '!': 62,
         '"': 63,
         '#': 64,
         '$': 65,
         '%': 66,
         '&': 67,
         "'": 68,
         '(': 69,
         ')': 70,
         '*': 71,
         '+': 72,
         ',': 73,
         '-': 74,
         '.': 75,
         '/': 76,
         ':': 77,
         ';': 78,
         '<': 79,
         '=': 80,
         '>': 81,
         '?': 82,
         '@': 83,
         '[': 84,
         '\\': 85,
         ']': 86,
         '^': 87,
         '_': 88,
         '`': 89,
         '{': 90,
         '|': 91,
         '}': 92,
         '~': 93}

# Take a string and base to convert to.
# Allocate space to store your number.
# For each character in your string:
#     Ensure character is in your table.
#     Find the value of your character.
#     Ensure value is within your base.
#     Self-multiply your number with the base.
#     Self-add your number with the digit's value.
# Return the number.

integer = 0
for character in innitvar:
    assert character in SY2VA, 'Found unknown character!'
    value = SY2VA[character]
    assert value < basevar, 'Found digit outside base!'
    integer *= basevar
    integer += value

# Create a value-to-symbol table.
VA2SY = dict(map(reversed, SY2VA.items()))

# Take a integer and base to convert to.
# Create an array to store the digits in.
# While the integer is not zero:
#     Divide the integer by the base to:
#         (1) Find the "last" digit in your number (value).
#         (2) Store remaining number not "chopped" (integer).
#     Save the digit in your storage array.
# Return your joined digits after putting them in the right order.

array = []
while integer:
    integer, value = divmod(integer, convertvar)
    array.append(VA2SY[value])
answer = ''.join(reversed(array))

# Display the results of the calculations.
print answer
Noctis Skytower
I have never used tables or the def and return functions before. And I'm afraid that converting to a base is my problem, as I still do not know how to access individual digits in a number in order to multiply and add.
Just a Student
`def` and `return` are two different keywords in Python, not functions. `def` allows you to create a function or method (a body of code that you can reuse by making "calls" to it), and `return` allows that body of code to return one or more values back to the "caller." As for accessing individual digits in a number, it helps to understand that there are no "individual digits" in a number. The base of a number does not matter so much as the value of the number. When you are converting a number into a representable base (a printable string for instance), you have to chop the number up by a base.
Noctis Skytower
What do you mean by "chop the number up by a base."? If I can't take the "1" out of "1234" and multiply it, then add the "2", how am I supposed to convert to base 10?
Just a Student
Again, you are thinking in "individual digits." Please do not think about the digits in your number. The `str2int` function above return a number of the `int` data type. This number has a value, but it does not have "digits" that you can access. For example, `a = 16` assigns the decimal value of `16` to `a`. However, the decimal value of `16` has a representation (not value) of `10` in hexadecimal. Thinking about the value of the number regardless of the base or representation would be very helpful to you. Knowing the decimal "representation" is fine, but think in terms of the "value" instead.
Noctis Skytower
I'm just becoming more and more confused. I have been trying to figure this out for hours now, but I cannot understand how to convert a base X number to base 10 using python code.
Just a Student
What does the function `str2int` up above do? It converts a base X number having a string representation into a number having a value. That is what you want. The number that is returned from the function does not have a base; it has a value. Take that value and use `divmod` to create the values for the digits of the base that you are converting the value of the number into. A string representation of a number is just that: a representation. The number returned by the `str2int` function has a value -- and that is all. It is a number with a value; it has no base. You must convert it into a base.
Noctis Skytower
I'm sorry, I'm just very frustrated with this assignment. Would you be willing to give me an example of how this works so I can better understand it?
Just a Student
Okay, let's try "completing" the assignment and then try to figure out how it works after it is done. You have my apologies, but I must not be explaining this very well for your understanding. The solution to the problem is simple to me, so solving the problem and then reviewing the answer may be a better way to help you. Come back after a little while and look for the second part of the solution.
Noctis Skytower
The second half of the code is now available. Both parts are required, especially considering that the global variable `VA2SY` relies on the existence of `SY2VA` to be created. `VA2SY` could be defined as a list, tuple, or string and be more efficient; but to prevent confusion, it is defined as a dictionary with its key/value pairs reversed. If you have questions, please ask so that you can learn!
Noctis Skytower
Are your # notes explaining what is happening, or is it listing what still needs to be done? I'm asking because I did not see any input statements to get anything from the user. Sorry if this is a stupid question, my brain is more or less fried from stressing over this problem all night.
Just a Student
The notes are explaining what the code following it does. If you are allowed to use functions, then you should be able to use the code above as seen. You just need to make calls to `str2int` and `int2str`. However, if you need to write your program without functions, then you need to change the code so that "arguments" to the functions are named after the variables created at the top of your program. Otherwise, rename the variables created in the first three lines of your program. Then you should be able to remove the four spaces at before the lines in the functions. Finally, print the answer.
Noctis Skytower
Could you explain what you mean by "You just need to make calls to str2int and int2str." and "Then you should be able to remove the four spaces at before the lines in the functions."? A lot of this code is new to me, so I'm still figuring out what it all does. I am slowly learning though.
Just a Student
I'm also wondering if "integer" and "base" are the same as "innitvar" and basevar" in my first 3 lines. And what value represents.
Just a Student
Err, to clarify, by "value", I mean the variable that you named "value" in your program.
Just a Student
`value` in my code is the value of a digit from a number. It is not to be confused with the value of a number as a whole. To assemble a representation into the value of a number, you have to deal with the values of the individual digits. In `str2int`, it adds those values to the value of your the number `integer` after `integer` has been multiplied by the base. The `int2str` method, on the other hand, disassembles the value of a number into the individual values (or representation of values) into a number that can be read: a printable string. By the way, do not convert `innitvar` into a float.
Noctis Skytower
Would I be right to change your "integer" to innitvar and "base" to basevar? And would I leave value as it is? I'm still not sure what you mean by "call str2int and int2str", but I'll keep trying to figure it out in the two hours I have left to complete the assignment.
Just a Student
Also, I've tried changing integer to innitvar and base to basevar, and have tried printing innitvar and basevar, but they do not change.
Just a Student
They do not change in the output, rather.
Just a Student
A working program should be available now. Please make sure you figure out how it works and why it works as soon as possible (by this weekend). You are learning to program, and you are learning to think (like a programmer), but you will not learn if you do not take the time to understand what you are given. If you take this program and do not understand it, I have been a disservice to your teacher. If you figure out what the program is doing and why it was written the way it was, then you may learn something that you can use in programs you write in the future. I hope that helps you do better!
Noctis Skytower
Thank you for all of your help. I'll study over the program until I understand it completely.
Just a Student
+2  A: 

Just a Student, slow down with the idea of what you need. You may not need what you think you need.

Start at the beginning: the user inputs a number. The user inputs a base. These are both Strings. Say the base is 12, and the number is 1AB3. So you have a '1' in the 12^3 place, an 'A' in the 12^2 place, a 'B' in 12^1, and a '3' in the 12^0 (ones) place. If you want this number in base 10, you're going to need to add some numbers together.

Specifically, you need to add 1*12^3 + 10*12^2 + 11*12^1 + 3*12^0. Notice something here: you have 3,2,1,0. Which corresponds nicely to the LENGTH of the input string 1AB3. So probably a for loop would be helpful here. The user doesn't input an integer, they input a string. So you need the characters from the string, not the digits from the number.

How do you know what the symbols 'A' and 'C' represent in decimal notation? Look at the answer from Noctis Skytower!

So your first task is to figure out how to ITERATE THROUGH A STRING. Your second task is to figure out how to use the individual character values from your string to access the dictionary in Noctis Skytower's answer, and your third task is to figure out how to write a loop that takes advantage of that information.

philosodad
+1: Probably the most comprehensive answer to help this person understand, instead of just crapping out some response.
Andrew Sledge
Thanks for explaining the math behind the operations. Teachers do not teach what they assume the students already know. I focused on the language, but your teaching why numbers work the way they do should be much more helpful in the long run. :)
Noctis Skytower