I am a complete beginner to Python. I wrote some code to perform base conversion and I was wondering if there were better alternatives that were shorter to code (one-liners) or significantly faster. The code looks ugly and feels "non-Pythonic" though being a beginner I should not have any such opinion. Any feedback to improve the code would be appreciated. This is purely for learning purposes.
#!/usr/bin/env python
import math
def number_to_digits( number, radix ):
'Converts a number into a vector of digits in given radix'
digits = [0]*int(math.ceil(math.log(number,radix)))
for ii in range(len(digits)):
(number,digit) = divmod(number,radix)
digits[ii] = digit
return digits
def digits_to_number( digits, radix ):
'Converts a vector of non-negative digits in given radix into a number'
number = 0;
for ii in range(len(digits)-1,-1,-1):
number *= radix
number += digits[ii]
return number
if __name__ == '__main__':
try:
number = int(raw_input('Enter number: '))
if number <= 0: raise ValueError()
radix = int(raw_input('Enter radix: '))
if radix <= 0: raise ValueError()
digits = number_to_digits(number,radix)
print digits
number_again = digits_to_number(digits,radix)
if not number_again == number:
print 'test failed'
except ValueError:
print 'unexpected input'
A sample session on the terminal produces:
Enter number: 44
Enter radix: 6
[2, 1, 1]
It is easy to check that 2 + 1*6 + 1*6**2 == 44. Thanks!
Here's a nice recursive version that will convert up to hexadecimal from Problem Solving with Algorithms and Data Structures
def toStr(n,base):
convertString = "0123456789ABCDEF"
if n < base:
return convertString[n]
else:
return toStr(n//base,base) + convertString[n%base]
print(toStr(1453,16))
Python provides some built-in functions to convert a value represented in one Integer base to another Integer base. Integer is represented in four forms i.e. decimal, binary, octal, and hexadecimal form.
Python provides built-in bin() functions to convert from non-binary number to binary number, oct() function to convert from non-octal number to octal number and hex() function to convert from non-hexadecimal number to hexadecimal number. These functions return a string literal to represent the values.
You can learn these functions from the tutorial on Integer base Conversion Functions in Python
You can find (slightly) cleaner example in the following thread:
Python elegant inverse function of int(string,base).
Taking the top ranked example, you can clean it up a bit to:
def digit_to_char(digit):
if digit < 10:
return str(digit)
return chr(ord('a') + digit - 10)
def str_base(number, base):
while number > 0:
number, digit = divmod(number, base)
yield digit_to_char(digit)
Results in:
>>> list(str_base(44, 6))
['2', '1', '1']
If you don't care about bases larger than 10, it simplifies to:
def str_base(number, base):
if base > 10:
raise ValueError('Base must be less than 10')
while number > 0:
number, digit = divmod(number, base)
yield digit
>>> list(str_base(44, 6))
[2, 1, 1]
Related
I encountered an issue with my Python script that converts binary to decimals. The caveat with this script is that I can only use basic computational functions (+, -, *, /, **, %, //), if/else, and for/while loops.
Shown below is my script:
x = int(input("Enter your binary input: "))
z=0
while x != 0:
for y in range (0,20):
if (x % 2 == 0):
z += 0*2**y
x = int(x/10)
elif (x % 2 != 0):
z += 1*2**y
x = int(x/10)
print(z)
While my script works for binaries with short length (e.g., 1101 = 13), it does not work for long binaries (especially those that have a length of 20). For example, inputting a binary of 11111010010011000111, my script returns an output of 1025217 instead of 1025223.
Can anyone point me to my mistake?
Thank you in advance!
Floating arithmetic isn't perfect and has a precision limit.
11111010010011000111 / 10 gives 1.1111010010011e+18, which when converted to an integer will give you a wrong result and it snowballs from there.
>>> int(11111010010011000111 / 10)
1111101001001100032
The more binary digits you have, the more "off" your calcuations will be.
In order to avoid the problem you encountered, use floor division, ie, x // 10.
Or you can skip turning x into a number and do the necessary power calculations based off each binary digit and its position.
x = input("Enter your binary input: ")[::-1]
n = 0
# this would be more elegant with `enumerate()`, but I assume you can't use it
# same for `sum()` and a comprehension list
for i in range(len(x)):
n += int(x[i])*2**i
print(n)
You can use the following method
to multiple each of the binary digits with its corresponding value of 2 raised to the power to its index (position from right – 1) and sum them up.
binary = input('Binary number: ')
decimal = 0
binary_len = len(binary)
for x in binary:
binary_len = binary_len - 1
decimal += pow(2,binary_len) * int(x)
print(decimal)
input : 11111010010011000111
output : 1025223
More examples
You should not use int to convert any number if you have to write a number converter.
Just use string operations:
digits = input("Enter your binary input: ")
number = 0
for digit in digits:
number = number * 2 + (digit == "1")
print(number)
output
Enter your binary input: 11111010010011000111
1025223
So I'm creating a program to show number systems, however I've run into issues at the first hurdle. The program will take a number from the user and then use that number throughout the program in order to explain several computer science concepts.
When explaining my first section, number systems, the program will say what type of number it is. I'm doing this by converting the string into a float number. If the float number only has '.0' after it then it converts it into a integer.
Currently I'm using this code
while CorrectNumber == False:
try:
Number = float(NumberString) - 0
print (Number)
except:
print ("Error! Not a number!")
This is useful as it shows if the user has entered a number or not. However I am unsure how to now check the value after the decimal place to check if I should convert it into a integer or not. Any tips?
If the string is convertable to integer, it should be digits only. It should be noted that this approach, as #cwallenpoole said, does NOT work with negative inputs beacuse of the '-' character. You could do:
if NumberString.isdigit():
Number = int(NumberString)
else:
Number = float(NumberString)
If you already have Number confirmed as a float, you can always use is_integer (works with negatives):
if Number.is_integer():
Number = int(Number)
Not sure I follow the question but here is an idea:
test = ['1.1', '2.1', '3.0', '4', '5', '6.12']
for number in test:
try:
print(int(number))
except ValueError:
print(float(number))
Returns:
1.1
2.1
3.0
4
5
6.12
Here is the method to check,
a = '10'
if a.isdigit():
print "Yes it is Integer"
elif a.replace('.','',1).isdigit() and a.count('.') < 2:
print "Its Float"
else:
print "Its is Neither Integer Nor Float! Something else"
This checks if the fractional-part has any non-zero digits.
def is_int(n):
try:
float_n = float(n)
int_n = int(float_n)
except ValueError:
return False
else:
return float_n == int_n
def is_float(n):
try:
float_n = float(n)
except ValueError:
return False
else:
return True
Testing the functions:
nums = ['12', '12.3', '12.0', '123.002']
for num in nums:
if is_int(num):
print(num, 'can be safely converted to an integer.')
elif is_float(num):
print(num, 'is a float with non-zero digit(s) in the fractional-part.')
It prints:
12 can be safely converted to an integer.
12.3 is a float with non-zero digit(s) in the fractional-part.
12.0 can be safely converted to an integer.
123.002 is a float with non-zero digit(s) in the fractional-part.
Regular expressions are nice for this as they can be custom tailored in case you have some edge-cases. For example:
How do you want to handle padded numbers (numbers with leading zeros). My example here includes this consideration.
Do you need to handle exponents, e.g. 2.3E12 or 2.3e12. This is not handled here.
...in other words, if your implementation doesn't agree with an assumption mine makes, you can change it.
Regular expressions work in all versions of Python (and other languages). They can be compiled for reuse, so should be pretty quick.
# Int is:
# - Only numbers that do NOT start with 0 (protect padded number strings)
# - Exactly 0
re_int = re.compile(r"(^[1-9]+\d*$|^0$)")
# Float is:
# - Only numbers but with exactly 1 dot.
# - The dot must always be followed number numbers
re_float = re.compile(r"(^\d+\.\d+$|^\.\d+$)")
These tests all pass:
def test_re_int(self):
self.assertTrue(re_int.match("1"))
self.assertTrue(re_int.match("1543"))
self.assertTrue(re_int.match("0")) # Exactly 0 is good
self.assertFalse(re_int.match("1.54"))
self.assertFalse(re_int.match("1a4"))
self.assertFalse(re_int.match("14a"))
self.assertFalse(re_int.match("a14"))
self.assertFalse(re_int.match("00")) # Ambiguous
self.assertFalse(re_int.match("0012")) # Protect padding
def test_re_float(self):
self.assertTrue(re_float.match("1.0"))
self.assertTrue(re_float.match("1.456"))
self.assertTrue(re_float.match("567.456"))
self.assertTrue(re_float.match("0.10"))
self.assertTrue(re_float.match(".10"))
self.assertFalse(re_float.match("1.0.0")) # Too many dots
self.assertFalse(re_float.match(".10.0"))
self.assertFalse(re_float.match("..034"))
self.assertFalse(re_float.match("1"))
self.assertFalse(re_float.match("0"))
self.assertFalse(re_float.match("1a4"))
self.assertFalse(re_float.match("14a"))
self.assertFalse(re_float.match("a14"))
self.assertFalse(re_float.match("1.a4"))
self.assertFalse(re_float.match("1.4a"))
self.assertFalse(re_float.match(".a14"))
Please comment if there are any caveats, missing details or regular expression improvements I can make.
Here's my gist that not only checks for positive & negative ints, but also checks for positive & negative floats. It also checks if the string is just a normal non-number.
def int_float_or_string(string):
try:
int(string) # strict and nice
except ValueError:
if is_strictly_float(string): # float() is too permissive, this is better
return "float"
else:
return "string"
else:
return "int"
def is_strictly_float(string):
if string.startswith("-"):
string = string[1:]
return "." in string and string.replace(".", "", 1).isdecimal()
int() is great for checking an integer, but float() has a problem of being too laid back in what it calls a float.
x=input("Enter a value to check it's type: ")
def checknumber(a):
try:
a=float(a)
if int(a)/a==1:
print("This is Integer")
return a
elif a/int(a)>1:
print("This is Float")
return a
except ValueError:
print("This value is String")
return str(a)
x=checknumber(x)```
I rewrite bin Mohammed's answer as follows (number also may be negative):
from numpy import nan, isnan
def is_valid_number(s):
if (s.find('-') <= 0) and s.replace('-', '', 1).isdigit():
if (s.count('-') == 0):
s_type = 'Positive Integer'
else:
s_type = 'Negative Integer'
elif (s.find('-') <= 0) and (s.count('.') < 2) and \
(s.replace('-', '', 1).replace('.', '', 1).isdigit()):
if (s.count('-') == 0):
s_type = 'Positive Float'
else:
s_type = 'Negative Float'
else:
s_type = "Not alphanumeric!"
return('{}\t is {}'.format(s, s_type))
example:
nums = ['12', '-34', '12.3', '-12.0', '123.0-02', '12!','5-6', '3.45.67']
for num in nums:
print(is_valid_number(num))
result:
12 is Positive Integer
-34 is Negative Integer
12.3 is Positive Float
-12.0 is Negative Float
123.0-02 is Not alphanumeric!
12! is Not alphanumeric!
5-6 is Not alphanumeric!
3.45.67 is Not alphanumeric!
minimal code:
from numpy import nan, isnan
def str2num(s):
if (s.find('-') <= 0) and s.replace('-', '', 1).isdigit():
return(int(s))
elif (s.find('-') <= 0) and (s.count('.') < 2) and \
(s.replace('-', '', 1).replace('.', '', 1).isdigit()):
return(float(s))
else:
return(nan)
example:
nums = ['12', '-34', '12.3', '-12.0', '123.0-02', '12!','5-6', '3.45.67']
for num in nums:
x = str2num(num)
if not isnan(x):
print('x =', x) # .... or do something else
result:
x = 12
x = -34
x = 12.3
x = -12.0
So I am meant to write a program that will convert a decimal to a binary and then another that will do the opposite. I know there are python functions to do this, but I think we are meant to do it the longer way. The pseudocode goes like this:
Decimal to Binary:
number = Prompt user for input, convert to int
Set quotient equal to number, remainder equal to zero
while(number!=0)
(quotient,remainder)=divmod(quotient,2)
print(remainder)
Binary to Decimal
number=Prompt user for input
Get string length of number = n
for x in range(n)
sum+=(2^n) times x
print sum
Any help?
Codes for manually converting. Am using loops here. It can be done using recursion too.
#Binary to Decimal
def btod(binary):
decimal = 0
for digit in binary:
decimal = decimal*2 + int(digit)
return decimal
#Decimal to Binary
def dtob(decimal):
if decimal == 0:
return 0
binary=''
decimal = int(decimal) #incase arg is int
while (decimal > 0):
binary+= str(decimal%2)
decimal = int(decimal/2)
return binary[::-1] #reverse the string
print(btod('101'))
#5
print(dtob('5'))
#101
The translation dictionary for your pseudo-code:
"Prompt user for input, convert to int":
int(input("Enter a decimal number: "))
"Set quotient equal to number, remainder equal to zero":
quotient = number
remainder = 0
"divmod(quotient,2)":
quotient // 2, quotient % 2
"Prompt user for input":
input("Enter a binary number: ")
"Get string length of number = n":
n = len(number)
"(2^n) times x":
2**n * x
"print sum":
print(sum)
Use this dictionary for replacing the corresponding parts in your pseudo-code. All other parts keep in their place, including indentations.
Note:
By your pseudo-code your program "Decimal to Binary" will print the converted decimal number in the column - read the result from bottom to top.
OK so this is my code, it's a base calculator that will convert base to base with no problem, but once the answer is over 9, I want the number to be represented as a letter, just like in base 16, 10 represent 'a', so I'm stuck on how can I do that just using Ascii tables. Right now the code is running well, if I type 1011,base2, I want to convert to base 16. So the output turns out to be 11, which is correct, but I want it to be 'b'
number = input("what's your number: ")
o_base = int(input("what is your oringal base: "))
base = int(input("what's the base you want to convert: "))
answer = ""
total = 0
for i, d in enumerate(reversed(number)):
total = total + int(d) * o_base ** i
while (total != 0):
answer += str(total % base)
total //= base
print (answer)
Python can first convert your number into a Python integer using int(number, base). Next all you need to do is convert it into you target base. This is often done using divmod() which combines doing a division of two numbers and getting their remainder into one function.
To convert each digit into the correct number or letter, the easiest way is to create an string holding all of your required symbols in order, and then use an index into this to give you the one you need, e.g. digits[0] here will return 0, and digits[10] would return A.
import string
number = input("What's your number: ")
o_base = int(input("What is your original base: "))
base = int(input("What is the base you want to convert to: "))
number = int(number, o_base)
digits = string.digits + string.ascii_uppercase # 0 to 9 + A to Z
output = []
while number:
number, remainder = divmod(number, base)
output.insert(0, digits[remainder])
print(''.join(output))
This example works up to base 36 (i.e. 0 to 9 and A to Z). You could obviously extend digits to give you more symbols for higher bases.
Using a list to create the output avoids doing repetitive string concatenation which is not very efficient.
decimal = input("Please insert a number: ")
if decimal > 256:
print "Value too big!"
elif decimal < 1:
print "Value too small!"
else:
decimal % 2
binary1 = []
binary0 = []
if decimal % 2 == 0:
binary1.append[decimal]
else:
binary0.append[decimal]
print binary1
print binary0
So Far, I want to test this code, it says on line 13:
TypeError: builtin_function_or_method' object has no attribute
__getitem__.
I don't understand why it is wrong.
I would like to convert the decimal number into binary. I only wanted to try and get the first value of the input then store it in a list to use then add it to another list as either a 0, or a 1. And if the input doesn't divide by 2 equally, add a zero. How would I do this?
binary1.append[decimal]
You tried to get an element from the append method, hence triggering the error. Since it's a function or method, you need to use the appropriate syntax to invoke it.
binary1.append(decimal)
Ditto for the other append call.
In response to your binary question. It is possible to brute-force your way to a solution quite easily. The thinking behind this is we will take any number N and then subtract N by 2 to the biggest power that will be less than N. For instance.
N = 80
2^6 = 64
In binary this is represented as 1000000.
Now take N - 2^6 to get 16.
Find the biggest power 2 can be applied to while being less than or equal to N.
2^4 = 16
In binary this now represented as 1010000.
For the actual code.
bList = []
n = int(raw_input("Enter a number"))
for i in range(n, 0, -1): # we will start at the number, could be better but I am lazy, obviously 2^n will be greater than N
if 2**i <= n: # we see if 2^i will be less than or equal to N
bList.append(int( "1" + "0" * i) ) # this transfers the number into decimal
n -= 2**i # subtract the input from what we got to find the next binary number
print 2**i
print sum(bList) # sum the binary together to get final binary answer