Are two integers equal in SOME base? - python

Disclaimer: this problem is purely for fun. There may already be a solution (I've searched, no luck). I have several questions below, I'd appreciate an answer to any of them. RIYL...
I was inspired by a Three Stooges video I saw earlier, where it's shown that 13x7 = 28. You may have seen it. But I started wondering: is there SOME "base" in which this equation is true (I put base in quotations because I'm using the term in the wrong sense..see the final paragraph for what I mean)?
The answer is clearly no, if we define multiplication the same as for integers. If you break up 13 into "base" i, say 13 = 1*i+3, and 28 = 2*i+8, the multiplication factor of 7 ensures equality won't happen.
Okay, but now suppose you want to ask the question, is there some base where two numbers are equal, say 8 = 10 (I'm probably using the term "base" wrong, sorry for that)?
What I mean is, if we write 8 = 008 = 0*8^2+0*8+8, 10 = 010 = 0*8^2+1*8^1+0, then according to my (clearly wrong) usage of base, we have equality. I wrote some simple code, up to 3 digit numbers, to verify this. But my code sucks.
''' We define two numbers, such that n1 > n2...tho I'm flexible'''
n1 = "013"
n2 = "025"
''' Set the numbers as arrays. '''
num1 = list(range(len(n1)))
num2 = list(range(len(n2)))
for i in range(len(n1)):
num1[i] = int(n1[i])
for i in range(len(n2)):
num2[i] = int(n2[i])
''' Now we loop until we find a match, or no match is possible. '''
i = 1
j = 0
while True:
t1=(num1[0]*(i**2)+num1[1]*i+num1[2])
t2=(num2[0]*(i**2)+num2[1]*i+num2[2])
''' We need some way to check if t1 > t2 changes to t1 < t2 at some point
or vise-versa -> then we know no match is possible '''
if(i == 1):
if t1>t2:
j = 0
else: j = 1
if(t1==t2):
print("The numbers are equal in base %d" % i)
break
if(t2 > t1 and j == 0):
print("No base possible! After %d steps" % i)
break
if(t1 > t2 and j == 1):
print("No base possible! After %d steps" % i)
break
i=i+1
if (i > 2**6):
print("your search might be hopeless")
break
Sorry if your eyes hurt from that hideous code. I didn't even use numpy arrays. What I'm wondering is,
Has this problem been solved before, for arbitrary digits? If not..
I wanted to be flexible about the number of digits entered in n1 and n2. Is there a more clever way to define the functions t1 and t2 so that they adaptively expand in base i, depending on the number of digits entered?
Performance-wise I'm sure there's a better way to do my main iteration. This is the fun part for me, combined with the answer to part 2. Any suggestions?
If it happens that t1 and t2 forever remain ordered the same, as in the example from the code, the iteration will play out 2^^6 times. The iteration number was chosen arbitrarily, but one could imagine if we extended to many digits, one might need even more iterations! Surely there's a more clever way to stop the iteration?
Is my stopping condition just wrong?
Thanks so much for reading. This is not a homework assignment and the answers are probably completely useless. I'm just interested in seeing a real coder's take on it. It would be neat if this wasn't an already-solved problem. Much love.

You can make the problem simpler by applying a little bit of number of theory. Taking your first example 13x7=28 we can expand this out into an explicit polynomial over the base: (1n+3)*7=2n+8.
If this solution has real roots then the roots are values of n (bases) for which the equation is true. If you like this sort of problem then you should read Computational Number Theory by Shoup. It's a fun book.

Related

Binary-like search

It's theoretical question.
exercise from leetcode as basis.
My solution for task is binary search. But question is not about it.
I found perfect solution on Discuss tab.
(next code has been taken from there)
class Solution:
def mySqrt(self, x: int) -> int:
low, high= 1, x
while low<high:
high = (low + high) // 2
low = x // high
return high
It works perfect. My question is:
For regular binary search we take middle of sequence and depending of comparison result remove excessive part (left or right) next repeat till result.
What is this implementation based on?
This solution cut part of sequence right after middle and small part from start.
This code isn't based on binary search. It's based instead on adapting the ancient "Babylonian method" to integer arithmetic. That in turn can be viewed as anticipating an instance of Newton's more-general method for finding a root of an equation.
Keeping distinct low and high variables isn't important in this code. For example, it's more commonly coded along these lines:
def intsqrt(n):
guess = n # must be >= true floor(sqrt(n))
while True:
newguess = (guess + (n // guess)) // 2
if guess <= newguess:
return guess
guess = newguess
but with more care taken to find a better initial guess.
BTW, binary search increases the number of "good bits" by 1 per iteration. This method approximately doubles the number of "good bits" per iteration, so is much more efficient the closer the guess gets to the final result.
This method is subtle, though was known of the Babylonians (see Tim's answer).
Assume that h > √x. Then
l = x/h < √x and
(l+h)/2 > √x.
The first property is obvious. For the second, observe that 1. and 2. imply
x+h² > 2h√x or (h-√x)^2 > 0, which is true.
So h remains above √x, but it gets closer and closer (because (l+h)/2 < h). And when the computation is made with integers, there is a moment such that l≥h.
How was this method discovered ?
Assume that you have an approximation h of √x and we want to improve it, with a correction δ. We write x = (h-δ)² = h²-2hδ + δ² = x. If we neglect δ², then we draw h-δ = (h²+x)/2h = (h+x/h)/2, which is our (h+l)/2.

Subtracting two numbers of any base between 2 and 10

For two numbers x and y that are base b, does this work for subtracting them? The numbers are given in string format and 2 <= b <= 10.
def n2b(n, b): # function to convert number n from base 10 to base b
if n == 0:
return 0
d = []
while n:
d.append(int(n % b))
n /= b
return ''.join(map(str,d[::-1]))
x = int(x,b) # convert to integers in base 10
y = int(y,b)
z = x - y
z = n2b(z,b) # convert back to base b, still in integer form
You have some confusion about how integers work in python. As the comments above say: python always stores integers in binary form and only converts them to a base when you print them. Depending on how you get x and y and how you need to give back z the code needs to be different
Situation 1: x, y and z are all integers
In this case you only need to do
z = x - y
And you're done.
Situation 2: x, y and z are all strings
In this case you first need to convert the strings into integers with the right base. I think that's your case, since you already deal with int(x, b) which is correct to transform a string into an integer (e.g. int("11", 2) gives 3 (integer represented in base 10). I would advice you to reform your code into something like this:
x_int = int(x, b)
y_int = int(y, b)
z_str = n2b(x_int - y_int, b)
In your code x is first a string and then an integer, which is bad practice. So e.g. use x_int instead of x.
Now it comes down to if your n2b function is correct. It looks good from the distance, although you're not handling signs and bases bigger than 10. There is a broadly accepted convert integer to base b answer so you might take this to be sure.
This is exactly the problem I just ran into in the google foobar challenge (which I suspect is the same source of ops problem). Granted its years later and op has no use for my answer but someone else might.
The issue
The function op used looked a lot like a copy and paste of this provided by the accepted answer but slightly modified (although I didn't look to closely).
I used the same function and quickly realized that I needed my output to be a string. Op appears to have realized the same thing based on the return statement at the end of the function.
This is why most of the test cases passed. Op did almost everything right.
See, the function begins with
if n==0:
return 0
One of the test cases in the foobar challenge uses 0 as the input. Its an easy line to miss but a very important one.
Solution
When I was presented this problem, I thought about the possible outlier cases. 0 was my first idea (which turned out to be right). I ran the program in vscode and would ya look at that - it failed.
This let me see the error message (in my case it was a list rather than int but op would have received a similar error).
The solution is simply changing return 0 to return '0' (a string rather than int)
I wasn't super excited to write out this answer since it feels a bit like cheating but its such a small detail that can be so infuriating to deal with. It doesn't solve the challenge that foobar gives you, just tells you how to get past a speed bump along the way.
Good luck infiltrating commander lambda's castle and hopefully this helps.

Solving recursive sequence

Lately I've been solving some challenges from Google Foobar for fun, and now I've been stuck in one of them for more than 4 days. It is about a recursive function defined as follows:
R(0) = 1
R(1) = 1
R(2) = 2
R(2n) = R(n) + R(n + 1) + n (for n > 1)
R(2n + 1) = R(n - 1) + R(n) + 1 (for n >= 1)
The challenge is writing a function answer(str_S) where str_S is a base-10 string representation of an integer S, which returns the largest n such that R(n) = S. If there is no such n, return "None". Also, S will be a positive integer no greater than 10^25.
I have investigated a lot about recursive functions and about solving recurrence relations, but with no luck. I outputted the first 500 numbers and I found no relation with each one whatsoever. I used the following code, which uses recursion, so it gets really slow when numbers start getting big.
def getNumberOfZombits(time):
if time == 0 or time == 1:
return 1
elif time == 2:
return 2
else:
if time % 2 == 0:
newTime = time/2
return getNumberOfZombits(newTime) + getNumberOfZombits(newTime+1) + newTime
else:
newTime = time/2 # integer, so rounds down
return getNumberOfZombits(newTime-1) + getNumberOfZombits(newTime) + 1
The challenge also included some test cases so, here they are:
Test cases
==========
Inputs:
(string) str_S = "7"
Output:
(string) "4"
Inputs:
(string) str_S = "100"
Output:
(string) "None"
I don't know if I need to solve the recurrence relation to anything simpler, but as there is one for even and one for odd numbers, I find it really hard to do (I haven't learned about it in school yet, so everything I know about this subject is from internet articles).
So, any help at all guiding me to finish this challenge will be welcome :)
Instead of trying to simplify this function mathematically, I simplified the algorithm in Python. As suggested by #LambdaFairy, I implemented memoization in the getNumberOfZombits(time) function. This optimization sped up the function a lot.
Then, I passed to the next step, of trying to see what was the input to that number of rabbits. I had analyzed the function before, by watching its plot, and I knew the even numbers got higher outputs first and only after some time the odd numbers got to the same level. As we want the highest input for that output, I first needed to search in the even numbers and then in the odd numbers.
As you can see, the odd numbers take always more time than the even to reach the same output.
The problem is that we could not search for the numbers increasing 1 each time (it was too slow). What I did to solve that was to implement a binary search-like algorithm. First, I would search the even numbers (with the binary search like algorithm) until I found one answer or I had no more numbers to search. Then, I did the same to the odd numbers (again, with the binary search like algorithm) and if an answer was found, I replaced whatever I had before with it (as it was necessarily bigger than the previous answer).
I have the source code I used to solve this, so if anyone needs it I don't mind sharing it :)
The key to solving this puzzle was using a binary search.
As you can see from the sequence generators, they rely on a roughly n/2 recursion, so calculating R(N) takes about 2*log2(N) recursive calls; and of course you need to do it for both the odd and the even.
Thats not too bad, but you need to figure out where to search for the N which will give you the input. To do this, I first implemented a search for upper and lower bounds for N. I walked up N by powers of 2, until I had N and 2N that formed the lower and upper bounds respectively for each sequence (odd and even).
With these bounds, I could then do a binary search between them to quickly find the value of N, or its non-existence.

NameError: name 'z' is not defined

I am trying to make a binary to decimal coverter for a project in my computing class and I get this error with my code: "NameError: name 'z' is not defined" I've looked up answers and they fix one error but give another. Here is the code:
bd = input("""
Would you like to convert a number into:
a) Binary to Decimal
b) Decimal to Binary
""")
if bd == 'a':
answer = input("""
Please enter a Binary number. Up to, and including, 8 digits of 1 and 0
""")
z += 2
for i in range(8):
if answer [ i ] == '1':
answer += 1*z**i
Any help would very much be appreciated!
Is this your first programming language? If so, let me introduce you to the concept of Variable Initialization.
When a computer is running code, it is processing bytes between the memory and the CPU. You probably know this already, but what you may not realize is that in your code, you are asking the computer to perform an operation on z, a variable that does not exist yet.
Keep something else in mind. Python does not need to initialize a variable in order to assign to it. So, why do you need to initialize z then before the program will run? The answer is simple: your first reference to z is an operation. Even though Python can automatically (without initialization) assign variables on the fly (different from other programming languages, usually), it still needs said variable to exist before math can be done with it.
The simple solution is to add z = 0 at any point before if bd == 'a': (because if you put it after, every time it goes into the if statement, it will over-write z with 0, ruining the logic for it.
Happy coding!
EDIT: In addition to this issue, the problem you will face with the error:
File "C:/Users/<USERNAME>/Desktop/Task 1.py", line 15, in <module> answer += 1*z**i TypeError: Can't convert 'int' object to str implicitly
Comes from the line:
if answer [ i ] == '1':
You see, when you type '1', you are saying that 1 is a string because you surround it with quotes, just the same as if you had written:
if answer [i] == "1":
What you need, instead, is the line
if answer [i] == 1:
Because that tells it to assign the number 1. Then, in the operation
answer += 1*z**i
You will be telling it to multiply three numbers instead of two numbers and the string "1".
In other languages like C, you must declare variables so that the computer knows the variable type. You would have to write string variable_name = "string text" in order to tell the computer that the variable is a string. In Python, the type casting happens automatically. Python sees variable = "string text" and it knows that because you used "", it is a string-type variable. Unfortunately, this means that you mistakenly made 1 a string.
Understand?
EDIT 2: The Happening
Okay, so you kept running into errors. And when I ran your code, I kept running into different errors. Because the of the tricky syntax and changing in types implicitly, I decided a much easier route to go was to rewrite the code and explain to you how and why it works. So, here is the new code:
bd = raw_input("""
Would you like to convert a number into:
a) Binary to Decimal
b) Decimal to Binary
""").lower()
## ORIGINAL CODE
##
##if bd == 'a':
## answer = input("""
##Please enter a Binary number. Up to, and including, 8 digits of 1 and/or 0
##""")
##
## print answer
## for i in range(8):
## z += 2
## if answer[i] == '1':
## answer += 1*z**i
##NEW CODE
if bd == 'a':
number_original = raw_input("Please enter a Binary number (a string of 1's and 0's)")
j = 0
number_converted = 0
for i in reversed(number):
if i == '1':
number_converted += 2**j
j+=1
print number_converted
From top to bottom, I'll go over what I wrote (I'll skip over your code) and I'll explain what it does and how it does it. Hopefully, this will help you in the decimal->binary conversion, as I assume you still have that to do.
So we begin with a few changes to your opening question. Where before you had bd=input(""), you now have bd=raw_input("").lower().
bd will still be a or b. But there was some shaky type handling in that statement, at least on my end. So, I made use of raw_input() which turns your answer into a string regardless of what it is. If you answer with 101010011 for instance, it will store the variable "101010011" and not the number 101010011 (though this would be wrong anyway-- it would be base 10, so it would actually be 101,010,011)... I also added .lower(), which as you may guess, turns your answer from whAtevErYouWritE to whateveryouwrite. This is an example of data sanitation and is vital in a good program, because people can be stupid and expect a computer to know what they mean. Computers, of course, have no idea what you mean, so you have to be very careful, know what mistakes a user can make, and plan ahead for it (BONUS: Here's a comic on the subject, which you will now definitely get).
So onto the meat of the program. We start by testing the condition for answer a with:
if bd == 'a':
Now, if you put in A, this would still work because of .lower(). If you put b, if wouldn't work (you have yet to put in your decimal->binary code!), and always remember that some day, someone will put in C, just to troll you, so include an elif for b and an else for anything else.
After this we encounter the first signs of it just being my code.
number_original = raw_input("Please enter a bin...
I've named it number_original because in code, it's always best practice to be clear and concise. Remember, the variable name this_is_the_variable_i_use_to_calculate_my_circumference is better than x so long as it explains clearly what it is, and helps other people understand your work. More advanced coders like to be ambiguous in this case, but a lot of the time it's just showing off.
I used raw_input() again because I actually want my number to be stored as a string. Remember when I said that 101010011 would be 101,010,011 to the computer? This would be very difficult to check, because the computer will assume a base 10 number. Thus, I just had it stored as a string, "101010011", and avoided that whole issue. There is also the added bonus to this that strings have manipulating methods that make it easier to work with, easier than the logic you were trying to introduce with range(8). That manipulator can be seen shortly.
Next, we declare our variables:
j = 0 #This 'j' accomplishes the same work done by your 'z' variable.
number_converted = 0 #this will be correctly converted by the end, as we add to it.
As mentioned in my original version of this post, these are initialized because the first time you operate on them inside the loop, you do math to them, and they need to exist as a number before you can do that. Even if they start at 0.
So now we look at the most interesting part, the for loop. Based on your original work, you kind of get how for loops work, but I'll go over them in a lot of detail so that hopefully, it helps you as much as possible when you need to see the big picture.
In a for loop, you are meant to iterate over a range of numbers. In your original code, you generated the range [0,1,2,3,4,5,6,7] to iterate over. I think you did this so you could keep track of which position in the binary number you were at, and I'm doing that as well, but in a different way, and one that I devised slowly in order to help you make the best decimal-to-binary system I could.
First, remember that number is a string now, so `"101010011". Next, realize that strings have indexes that can be accessed like so.
demo_string = "super mario brothers"
print demo_string[0]
print demo_string[1]
print demo_string[2]
print demo_string[3]
print demo_string[4:10]
print demo_string[:10] #if you leave out the first number, it starts at the beginning
print demo_string[10:] #if you leave out the last number, it ends at the end.
The above code will give you the following result:
s
u
p
e
r mari
super mari
o brothers
Take special notice that an index starts at 0, which is why demo_string[1] is u and not s.
Knowing this, you may begin to realize why we left number_original as a string: now we can use its index and iterate over that instead of making our own range with range()! This is why we can type for i in reverse(number_original); because that makes it loop from reverse(number_original)[0] to reverse(number_original)[i], as far as i is able to go. **Note:***We will go over why we are using* reverse() shortly.
It's time for number/computer science and math!
Have you learned yet about expressing every binary digit in the form of a power of two? I know you understand the concept underlying conversion in a binary number. Well, here's another cool trick you may or may not be aware of:
... # # # # # # <--The binary number, eg "101010"
...32 16 8 4 2 1 <--What each digit stands for in decimal form
... 5 4 3 2 1 0 <--The power of two that it stands for (2^5=32, 2^4=16...)
Another thing you'll realize is that typically (not always, but usually, binary numbers are read from right to left. This will come in handy in a moment).
So we're at the for loop. We know now that we can iterate through a string. But binary digits are read right-to-left. So, the binary number 10 = 2, not 10 = 1. This is why we wrote:
for i in reversed(string):
Because now, the for loop will iterate backwards! It will read the string right-to-left for us.
We also know that 2^x = (digit value in decimal).
So what we'll do in each iteration of the for loop is:
Check if i == '1' Note, this time we want it to be a string.
If i == '1', as in, the digit we're highlighting is a '1', then...
Take number_converted and add number_converted + 2^j
Then accumulate once to j, so it's one higher for the next trip.
To put this visually, I'll do two loops on the number 101010011.
Loop 4
j = 4
number_converted = 3 (still being converted)
is reversed(number_original)[3] == '1'? ( 1 1 0 0 1 0 1 0 1, so no)
then add 1 to j (j = 5)
Loop 5
j = 5
number_converted = 3 (still being converted)
is reversed(number_original)[4] == '1'? (1 1 0 0 1 0 1 0 1, so yes!)
then take number_converted (3) and add 2^j (2^5 = 16) to it (number_converted = 25)
then add 1 to j (j = 6)
Loop 6
j = 6
number_converted = 35 (still being converted)
this will continue until end!
So there you have it. Binary to decimal, in python.
If you have any questions about this, please ask. I remember being confused about this stuff when I first started!
And again, Happy Coding.
You need to assign z to a value becore you can use +=
Add z = 0 to the top of your script.
You never initialized z, so if you put z = 0 on the line above the if statement, you'll no longer have the issue
bd = input("""
Would you like to convert a number into:
a) Binary to Decimal
b) Decimal to Binary
""")
z = 0
if bd == 'a':
answer = input("""
Please enter a Binary number. Up to, and including, 8 digits of 1 and 0
""")
z += 2
for i in range(8):
if answer [ i ] == '1':
answer += 1*z**i
You never defined z.Try this code:
z = 0
bd = raw_input("Would you like to convert a number into:\n a) Binary to Decimal\n b) Decimal to Binary")
if bd == 'a':
answer = raw_input("Please enter a Binary number. Up to, and including, 8 digits of 1 and 0")
z += 2
ex = 0
for i in xrange(8):
if answer[i] == '1':
ex += 1*z**i

How do I get the Math equation of Python Algorithm?

ok so I am feeling a little stupid for not knowing this, but a coworker asked so I am asking here: I have written a python algorithm that solves his problem. given x > 0 add all numbers together from 1 to x.
def intsum(x):
if x > 0:
return x + intsum(x - 1)
else:
return 0
intsum(10)
55
first what is this type of equation is this and what is the correct way to get this answer as it is clearly easier using some other method?
This is recursion, though for some reason you're labeling it like it's factorial.
In any case, the sum from 1 to n is also simply:
n * ( n + 1 ) / 2
(You can special case it for negative values if you like.)
Transforming recursively-defined sequences of integers into ones that can be expressed in a closed form is a fascinating part of discrete mathematics -- I heartily recommend Concrete Mathematics: A Foundation for Computer Science, by Ronald Graham, Donald Knuth, and Oren Patashnik (see. e.g. the wikipedia entry about it).
However, the specific sequence you show, fac(x) = fac(x - 1) + x, according to a famous anecdote, was solved by Gauss when he was a child in first grade -- the teacher had given the pupils the taksk of summing numbers from 1 to 100 to keep them quet for a while, but two minutes later there was young Gauss with the answer, 5050, and the explanation: "I noticed that I can sum the first, 1, and the last, 100, that's 101; and the second, 2, and the next-to-last, 99, and that's again 101; and clearly that repeats 50 times, so, 50 times 101, 5050". Not rigorous as proofs go, but quite correct and appropriate for a 6-years-old;-).
In the same way (plus really elementary algebra) you can see that the general case is, as many have already said, (N * (N+1)) / 2 (the product is always even, since one of the numbers must be odd and one even; so the division by two will always produce an integer, as desired, with no remainder).
Here is how to prove the closed form for an arithmetic progression
S = 1 + 2 + ... + (n-1) + n
S = n + (n-1) + ... + 2 + 1
2S = (n+1) + (n+1) + ... + (n+1) + (n+1)
^ you'll note that there are n terms there.
2S = n(n+1)
S = n(n+1)/2
I'm not allowed to comment yet so I'll just add that you'll want to be careful in using range() as it's 0 base. You'll need to use range(n+1) to get the desired effect.
Sorry for the duplication...
sum(range(10)) != 55
sum(range(11)) == 55
OP has asked, in a comment, for a link to the story about Gauss as a schoolchild.
He may want to check out this fascinating article by Brian Hayes. It not only rather convincingly suggests that the Gauss story may be a modern fabrication, but outlines how it would be rather difficult not to see the patterns involved in summing the numbers from 1 to 100. That in fact the only way to miss these patterns would be to solve the problem by writing a program.
The article also talks about different ways to sum arithmetic progressions, which is at the heart of OP's question. There is also an ad-free version here.
Larry is very correct with his formula, and its the fastest way to calculate the sum of all integers up to n.
But for completeness, there are built-in Python functions, that perform what you have done, on lists with arbitrary elements. E.g.
sum()
>>> sum(range(11))
55
>>> sum([2,4,6])
12
or more general, reduce()
>>> import operator
>>> reduce(operator.add, range(11))
55
Consider that N+1, N-1+2, N-2+3, and so on all add up to the same number, and there are approximately N/2 instances like that (exactly N/2 if N is even).
What you have there is called arithmetic sequence and as suggested, you can compute it directly without overhead which might result from the recursion.
And I would say this is a homework despite what you say.

Categories

Resources