Converting binary to decimal using only Boolean and logic comparisons - python

I am taking a Python Certification class and have taken two practice exams to prepare for the timed exam I will be scheduling soon. However, there is limited interaction with professors and the discussion board is mostly students. I have a question that has been on both practice exams, so I imagine it will be on the real exam as well, and I can not see to wrap my head around how to solve it. There is no way in the class to see how to solve coding problems you have gotten incorrect, which is a major disappointment as that helps me in the future. I know there are built in functions for solving binary/decimal conversions, but the professor is wanting this done using Boolean logic and numerical comparisons as we are still in the early stages of the course. If anyone could assist in "walking" through the why's of the answer I would greatly appreciate it. Thank you.
number = 1101
You may modify the lines of code above, but don't move them! When you
Submit your code, we'll change these lines to assign different values
to the variables.
The number above represents a binary number. It will always be up to
eight digits, and all eight digits will always be either 1 or 0.
The string gives the binary representation of a number. In binary,
each digit of that string corresponds to a power of
2. The far left digit represents 128, then 64, then 32, then 16, then 8, then 4, then 2, and then finally 1 at the far right.
So, to convert the number to a decimal number, you want to (for
example) add 128 to the total if the first digit is 1, 64 if the
second digit is 1, 32 if the third digit is 1, etc.
For example, 00001101 is the number 13: there is a 0 in the 128s
place, 64s place, 32s place, 16s place, and 2s place. There are 1s in
the 8s, 4s, and 1s place. 8 + 4 + 1 = 13.
Note that although we use 'if' a lot to describe this problem, this
can be done entirely boolean logic and numerical comparisons.
Print the number that results from this conversion.

number = "00001101" #in Python, leading zeros are not permitted, so use a string
total = 0 #this var will keep track of the number in decimal form
index = len(number)-1 #eg 1100 has 4 digits and the max power is 3, 2^3.
for str_digit in number: #for each digit (as a string) in the number,
#total += int(str_digit)* 2**index #add the value (0 or 1) multiplied by 2 raised to the index power
if int(str_digit): #either 'if 0' or 'if 1'
total += 2**index #add 2 raised to the index power
index -= 1 # decrease the index
print(total)
Note that the line if int(str_digit): is actually redundant if you use the commented line total += int(str_digit)* 2**index instead, but I included it because your question specified that you want to test the Boolean value.
This line is the same as if 0: or if 1: which is the same as if False: or if True:.

All you need is this:
int(number, base=2)

Related

Creating a unique short ID from string value

I have some data that has unique IDs stored as a string in the form:
ddd.dddddaddd.dddddz
Where d is some digit and a/z is some alphabet character. The digits may be 0-9 and the characters are either E or W for the a and N or S for the z.
I'd like to turn this into a unique integer and what I've tried using the hashlib module returns:
>>> int(hashlib.sha256(str.encode(s)).hexdigest(), 16)
Output: a very long integer (on another system cannot copy it)
Is there a way to generate a unique integer ID from a string so that it does not exceed 12 digits? I know that I will never need a unique integer ID beyond 12 digits.
Just something simple:
>>> s = '123.45678W123.45678S'
>>> int(s.translate(str.maketrans('EWNS', '1234', '.')))
123456782123456784
Not the impossible 12 digits you're still asking for in the question, but under the 20 digits you allowed in the comments.
As you are dealing with coordinates, I would try my best to keep the information in the final 12-digit ID.
If your points are global, it might be necessary to keep the degrees but they may be widespread, so you can sacrifice some information when it comes to precision.
If your points are local (all within a range of less than 10 degrees) you might skip the first two digits of the degrees and focus on the decimals.
As it may be possible that two points are close to each other, it may be prudent to reserve one digit as a serial number.
Proposal for widespread points:
s = "123.45678N123.45678E"
ident = "".join([s[0:6],s[10:16]]).replace(".","")
q = 0
if s[9]=="N":
q+=1
if s[-1]=="E":
q+=2
ident+=str(q)+'0'
The example would translate to 123451234530.
After computing the initial ident numbers for each ID, you should loop through them and increment the last digit if an ident is already taken.
This way you could easily reconstruct the location from the ID by just separating the first 10 digits to two degrees of the format ddd.dd and use the [-2] digit as an indicator of the quadrant (0:SW, 1:SE, 2:NW, 3:NE).

Combining functions to produce a desired integer output

I'm not sure if this question belongs on stackoverflow or math, but I'll give stackoverflow a shot.
I'm attempting to create an algorithm / function that will allow me to solve a puzzle, but I am simply unable to. The puzzle is as stated.
Let a unit be a function that accepts a integer i between 0 and 15.
A unit can add or subtract any number in the range 0 - 15 to/from i.
Additionally, instead of adding or subtracting a number to/from i, a unit can also contain a number from 0-15 and subtract i from that.
A unit can only perform 2 operations on a number, and the operation producing the largest value will be the output of the unit.
Values only go from 0 - 15, so 9 - 15 = 0 and 13 + 5 = 15.
We may combine units together to produce a more complex result.
The first unit may only accept numbers ranging from 0 - 9.
In my examples I will string together 3 units.
This is a problem that is unrelated to coding, but it seems that I need a program to figure out possible solutions. I've attempted to create a brute force algorithm to find solutions, but I've been unable to do so, as I'm not that great with coding.
For example, a problem could be:
For values 1 and 4, let the output be 0. For all others, e.g. 0, 2, 3, 5, 6, 7, 8, 9, the output must be greater than 0.
A solution here might be:
def unit1(input):
return max(5 - input, input)
def unit2(input):
max(14 - input, input)
def unit3(input):
max(10 - input, input - 10)
print(unit3(unit2(unit1(4))))
Another example might be:
For values 4, 5, 6 and 8 the output must be 3 or greater. For all others, e.g. 0, 1, 2, 3, 7, 9, the output must be less than 3.
A solution here might be:
def unit1(input):
return max(4 - input, input - 4)
def unit2(input):
max(2, input)
def unit3(input):
max(1 - input, input - 6)
print(unit3(unit2(unit1(5))))
Given an example as the two stated above, is there a general algorithm / formula I can use to find my desired output?
Additionally, is it possible to solve the problems above using only 2 units?
Please do let me know if I need to elaborate on something, and know that your help is extremely appreciated!
There seems to be basically two kinds of things you have to do: map inputs that should be handled the same way to contiguous ranges, and then move contiguous ranges to the right place.
max(A-x,x-B) is the only kind of unit that can map non-contiguous ranges together. It has limitations: It always maps 2 inputs onto one output, and you've gotta be careful never to map two inputs that have to be handled differently onto the same output.
In terms of what gets mapped together, you only need one parameter, since max(x,A-x) handles all cases. You can try all 16 possibilities to see if any of them help. Sometimes you may need to do a saturating add before the max to collapse inputs at the top or bottom of the range.
In your first example, you need to map 0 and 4 together.
In max(x,A-x), we need 4 = A-1.
Solving that we get A=5, so we start with
max(x, 5-x)
That maps 4 and 1 to 4, and everything else to other values.
Now we need to combine the ranges above and below 4. Everything less than 4 has to map to something higher than 4. We solve 5 = A-3 to get A = 8:
max(x, 8-x)
Now the ranges of things that need to be handled the same way are contiguous, so we just need to move them to the right place. We have values >=4 and we need 4->0. We could add a subtraction unit, but it's shorter just to shift the previous max by subtracting 4 from both cases. We're left with a final solution
max(x, 5-x)
max(x-4, 4-x)
You haven't really defined all the possible questions you might be asked, but it looks like they can all be solved by this two step combine-and-shift process. Sometimes there will be no solution because you can't combine ranges in any valid way with max.
I think your missing piece you need to proceed is a higher-order function. That's a function that returns another function. Something like:
def createUnit(sub, add):
def unit(input):
return max(sub - input, input + add)
return unit
You can use it like:
unit1 = createUnit(5, 0)
unit2 = createUnit(14, 0)
unit3 = createUnit(10, -10)
Your first example can be solved with two units, but your second example can't.
I think the key to solving this efficiently is to work backwards from the output to the input, but I haven't spent enough time on it to figure out precisely how to do so.

Why do I have to change integers to strings in order to iterate them in Python?

First of all, I have only recently started to learn Python on codeacademy.com and this is probably a very basic question, so thank you for the help and please forgive my lack of knowledge.
The function below takes positive integers as input and returns the sum of all that numbers' digits. What I don't understand, is why I have to change the type of the input into str first, and then back into integer, in order to add the numbers' digits to each other. Could someone help me out with an explanation please? The code works fine for the exercise, but I feel I am missing the big picture here.
def digit_sum(n):
num = 0
for i in str(n):
num += int(i)
return num
Integers are not sequences of digits. They are just (whole) numbers, so they can't be iterated over.
By turning the integer into a string, you created a sequence of digits (characters), and a string can be iterated over. It is no longer a number, it is now text.
See it as a representation; you could also have turned the same number into hexadecimal text, or octal text, or binary text. It would still be the same numerical value, just written down differently in text.
Iteration over a string works, and gives you single characters, which for a number means that each character is also a digit. The code takes that character and turns it back into a number with int(i).
You don't have to use that trick. You could also use maths:
def digit_sum(n):
total = 0
while n:
n, digit = divmod(n, 10)
num += digit
return num
This uses a while loop, and repeatedly divides the input number by ten (keeping the remainder) until 0 is reached. The remainders are summed, giving you the digit sum. So 1234 is turned into 123 and 4, then 12 and 3, etc.
Let's say the number 12345
So I would need 1,2,3,4,5 from the given number and then sum it up.
So how to get individuals number. One mathematical way was how #Martijn Pieters showed.
Another is to convert it into a string , and make it iterable.
This is one of the many ways to do it.
>>> sum(map(int, list(str(12345))))
15
The list() function break a string into individual letters. SO I needed a string. Once I have all numbers as individual letters, I can convert them into integers and add them up .

Split day-of-month integers into digits, sum them repeatedly until get a single-digit integer

I am attempting to take two-digit integers representing day-of-month, split the digits into single digits by taking each character in the single digit and adding them together to form a new number.
e.g. If the value for day was an integer 29, then the program would turn that into strings and split them into '2' and '9'. The program would then turn 2 and 9 into integers and add them together to equal 11. Since this is still a double digit number, the program would loop and 1 and 1 would be added together and the final value that would print would be 2. According to the code below(mostly the last ~5 lines), if I enter day=29, then the final answer I keep getting is 4 which is incorrect. Can someone help me fix this:
Note someone mentioned that I didn't re-enter dayStringSum and I accidentally deleted their post am not sure what that means at all.
dayString = str(int(day))
# Turns value day into int
dayStringA = int(str(dayString[0]))
# If day=29 then this variable represents the 2...
dayStringB = int(str(dayString[1]))
# ...and this represents the 9
dayStringSum = (dayStringA + dayStringA)
while(dayStringSum >=10):
dayStringA = int(str(dayStringSum[0]))
# Since daystringsum is now 11, this code changes the value of daystringA into a new value of 1, likewise for below.
dayStringB = int(str(dayStringSum[1]))
print(dayStringSum)
dayStringSum is an integer, so dayStringSum[n] makes no sense. You'll want to turn it into a string first, and then look at its individual characters.
Also, you do not assign a new value to dayStringSum inside the while loop, so if it is >= 10 upon entering the loop, it will remain so, resulting in an infinite loop. You say that you got a final result of 4, but I fail to see how you would get a final result at all.
Try something like this:
daySum = int(day) # Ensure that day is an int before we start.
while(daySum >= 10):
newString = str(daySum)
dayIntA = int(newString[0])
dayIntB = int(newString[1])
daySum = dayIntA + dayIntB # Will be checked on next iteration.
print(daySum)
I'm guessing the reason you're getting the wrong answer is that you add dayStringA + dayStringA when you meant to add dayStringA + dayStringB, i.e. it's just a typo.
The other thing you need to fix is that in the loop, you don't change dayStringSum. This hasn't been a problem so far because dayStringSum is less than 10 in your example, so the loop never executes in the first place, but once you fix that typo, you're going to get an infinite loop and the program will never stop.
Here's what I mean: suppose your day is 29. When you get to this line:
while(dayStringSum >=10):
then dayStringSum will be 11. So then you set dayStringA to 1,
dayStringA= int(str(dayStringSum[0]))
and also dayStringB to 1.
dayStringB= int(str(dayStringSum[1]))
Then that's the end of the loop. So Python goes back to this line:
while(dayStringSum >=10):
What's dayStringSum? Why, it's still 11! You never changed it. So Python will keep looping, going through the same logic over and over again.
Now beyond that, there are a bunch of things that make this code way more complicated than it needs to be. I'm not going to go through them (Code Review would be the place for that), but in general, you don't need to convert things to ints if they are already ints, and likewise you don't need to use str on something that is already a string.
try sum(map(int,"265"))
that maps them to ints and sums them ...
>>> sum(map(int,"254"))
11
or
>>> sum(map(int,str(29)))
11
oh well since its homework I cant really just give away the answer ....
but
its similar to
sum1=0
for integer in [1,2,3]: sum1 += integer
print sum1
Easier way is to take modulus 9 of the number
>>> print(29%9)
2
day = 29
while day >= 10:
day = sum(int(digit) for digit in str(day))
(Also, whenever you're doing major manipulations of the individual digits of an integer, decimal.Decimal is useful, in particular its method
Decimal(29).as_tuple().digits which gives you (2, 9)).

Why don't these simple Python programs work: Euler 4 and 9

I was trying Project Euler and am stuck on this one:
A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 99.
Find the largest palindrome made from the product of two 3-digit numbers.
for i in range(1000,100,-1):
for j in range(1000,100,-1):
test = i*j
test = str(test) #turn product into string
test2 = test[2:] #take last two numbers
test2 = test2[::-1] #flip them
if test[:2] == test2: #if it's a palindrome, the first two should
print(i, "\t", j) #match the flip of last two
input("\n\nPress the ENTER key to exit.")
Nothing happens when it is run: the command line calculates, but doesn't print anything. The program does end though.
I know the bigger numbers have more than just the first and last two numbers, but there should be few enough palindromes that I can just look through them.
Here is the next one:
Find the Pythagorean triplet whose sum is 1000.
a^2 + b^2 = c^2, a+b+c=1000
for a in range(1,32):
for b in range(1,32):
c = (a**2 + b**2)**.5
if a + b + c == 1000:
print(a,"\t",b,"\t",c)
input("\n\nPress the ENTER key to exit.")
As with the last program, there is no output... But again, it does end.
But I noticed that they both have nested for loops. Could this have something to do with it?
Both your tests are wrong. In the first example, the line
test2 = test[2:] #take last two numbers
does not say what the comment says – this line strips off the first two characters from the string, leaving only the last digit. Instead of fixing this line, simply check if the whole string equals the reversed string:
if test == test[::-1]:
In the second example, you compare approximate floating point numbers to the exact integer 1000. Since the floating-pointed numbers will have rounding errors, you don't find an exact match. See also Floating Point Arithmetic: Issues and Limitations in the Python tutorial.
You should round c to the nearest integer, check if they really are a Pythagorean triple using pure integer arithmetic and then test if the sum is 1000.
As pointed out by DSM in the comments, your loops also stop to early. the maximum sum you will find with these values is about 106.
With the second problem: simple mistake;c is a floating point number and you are comparing a+b+c to 1000;raising to a floating point number gives a floating point number e.g. (3**2+4**2)**0.5 == 5.0
For the second problem, you don't have a large enough range. If the maximum of a and b are 31, then the greatest value of c can be (31^2 + 31^2)^0.5, so the sum of a + b + c you can possibly have is (2 + sqrt(2) * 31, which is less than 1000.
As for the floating point issue, make sure that you use the int() function to turn c into an integer. This may produce some overlap with rounding errors (I don't think it did for me when I tried that solution), but it should be trivially easy to check the few results you do get for the correct one, even if you do it manually within the one-minute limit.

Categories