How to count horseshoes in python? - python

I've completely stuck with this task and I really dunno how to make this program work properly, because I think I've already tried many possible options, but it still unfortunately didn't work properly.
The task is: "The blacksmith has to shoe several horses and needs to see if he has the correct number of horseshoes. Write a check(p, k) function that, for a given number of horseshoes p and number of horses k, prints out how many horseshoes are missing, remaining, or whether the number is correct (see sample file for output format)."
The code I've already done is:
def check(p, k):
if p % 2 == 0 and k % 2 == 0 and p % k == 0:
print("Remaining:", k % p)
elif p % k != 0:
print("Missing:", p // k + 1)
else:
print("OK")
check(20, 6)
check(10, 2)
check(12, 3)
check(13, 3)
The output should look like this:
Missing: 4
Remaining: 2
OK
Remaining: 1

You could try this:
def check(shoes, horses):
if shoes > 4*horses:
print("Remaining:", shoes - 4 * horses)
elif shoes == 4*horses:
print("OK")
else:
print("Missing:", 4 * horses - shoes)

Try checking if you have the correct number first:
def check(p, k):
required_shoes = k * 4
if p == required_shoes:
# just right
elif p < required_shoes:
# not enough
else:
# too many

def check(p, k):
if p / k == 4:
print("OK")
elif p / k > 4:
print("Remaining:", p - 4 * k)
else:
print("Missing:", 4 * k - p)
check(20, 6) # Missing: 4
check(10, 2) # Remaining: 2
check(12, 3) # OK
check(13, 3) # Remaining: 1
This works in the given cases

Related

Improving the runinng time of a numerical algorithm by parallel computation, using gmpy2 module of Python

I'm working on a numerical algorithm as follows.
import timeit
import gmpy2
import math
A = gmpy2.mpz(1000007777)
# Input a positive integer to factor.
# Put it inside the parentheses as "A = gmpy2.mpz(....)"
def factor(A):
B = gmpy2.mpz(math.sqrt(2 * A + 0.25) - 1)
D = gmpy2.mpz(A - (B * B + B) / 2)
while (D > 0):
B += 1
D = gmpy2.mpz(A - (B * B + B) / 2)
n = gmpy2.mpz(0)
while (D != 0 and B <= A):
if (D > 0):
B += 1
D -= B
else:
n += 1
D += n
if B > A:
return output(0, 0, 0)
else:
print(f"[B={B}, n={n}]")
if (B - n) % 2 == 0:
E = gmpy2.mpz((B - n) / 2)
F = gmpy2.mpz(B + n + 1)
else:
E = gmpy2.mpz(B - n)
F = gmpy2.mpz((B + n + 1) / 2)
return output(A, E, F)
def output(A, E, F):
if A == 0:
print(f"Initial Value Error: Reset the B value")
else:
if A % E != 0 or A % F != 0 or A != E * F:
print(f"[Error Occurred] {A} != {E} * {F}")
else:
print(f"{A} = {E} * {F}")
return 0
if __name__ == '__main__':
if A >= 2:
timer_start = timeit.default_timer()
factor(A)
timer_stop = timeit.default_timer()
running_time = round(timer_stop - timer_start, 6)
print("running time: ", running_time, " seconds")
else:
print("undefined for A<2")
(Note that the output of B and n comes out as [B=21739322, n=21739276] with our argument in the example code)
The task of this code aims to reach 0 by adding and subtracting integers. The D value shall oscillate between 0 until it reaches 0. I wanted to improve the running time of this task by parallel computation, using multiprocessing module of Python.
import timeit
import gmpy2
import math
import multiprocessing
A = gmpy2.mpz(1000007777)
# Input a positive integer to factor.
# Put it inside the parentheses as "A = gmpy2.mpz(....)"
k = 4
# Input the number of cores to be used as "k=..."
# [!!Caveat!!] Don't use too much number of cores which exceeds the
# availability of CPU resources of your personal computer environment.
# It can damage the CPU !!!
def factor(n):
if A < 2:
print("undefined for A<2")
else:
B = gmpy2.mpz(math.sqrt(2 * A + 0.25) - 1)
D = gmpy2.mpz(A - (B * B + B) / 2)
while (D > 0):
B += 1
D = gmpy2.mpz(A - (B * B + B) / 2)
D += gmpy2.mpz(n * (n + 1) / 2)
while (D != 0 and B <= A):
if (D > 0):
B += 1
D -= B
else:
D += k * n + (k * (k + 1)) / 2
n += k
if B > A:
return output(0, 0, 0)
else:
if (B - n) % 2 == 0:
E = gmpy2.mpz((B - n) / 2)
F = gmpy2.mpz(B + n + 1)
else:
E = gmpy2.mpz(B - n)
F = gmpy2.mpz((B + n + 1) / 2)
return output(A, E, F)
def output(A, E, F):
timer_stop = timeit.default_timer()
running_time = round(timer_stop - timer_start, 6)
if A == 0:
print(f"Initial Value Error: Reset the B or k value \n")
else:
if A % E != 0 or A % F != 0 or A != E * F:
print(f"[Error Occurred] {A} != {E} * {F} \n")
else:
print(f"[running time: {running_time} seconds] {A} = {E} * {F} \n")
return 0
if __name__ == '__main__':
n = []
timer_start = timeit.default_timer()
with multiprocessing.Pool(processes=k) as pool:
for x in range(0, k):
y = gmpy2.mpz(x)
n.append(y)
results = pool.map(factor, n)
The idea behind this is that, executing some addition of integers until meeting its target value, which is 0 in our code, shall be done faster if the added size of integers becomes bigger. For example, it is quite obvious that adding integers as 4+4+4... is faster to reach 100 than adding integers as 1+1+1...
However, my numerical experiments have shown that the latter code of multiprocessing module is nowhere faster than the previous code of single-core.
But, noticing that the value n=21739276 of which we mentioned above is divisible by 4, I've tried the modification of single-core version code as follows
import timeit
import gmpy2
import math
A = gmpy2.mpz(1000007777)
# Input a positive integer to factor.
# Put it inside the parentheses as "A = gmpy2.mpz(....)"
def factor(A):
B = gmpy2.mpz(math.sqrt(2 * A + 0.25) - 1)
D = gmpy2.mpz(A - (B * B + B) / 2)
while (D > 0):
B += 1
D = gmpy2.mpz(A - (B * B + B) / 2)
n = gmpy2.mpz(0)
while (D != 0 and B <= A):
if (D > 0):
B += 1
D -= B
else:
D += 4*n+10
n += 4
if B > A:
return output(0, 0, 0)
else:
print(f"[B={B}, n={n}]")
if (B - n) % 2 == 0:
E = gmpy2.mpz((B - n) / 2)
F = gmpy2.mpz(B + n + 1)
else:
E = gmpy2.mpz(B - n)
F = gmpy2.mpz((B + n + 1) / 2)
return output(A, E, F)
def output(A, E, F):
if A == 0:
print(f"Initial Value Error: Reset the B value")
else:
if A % E != 0 or A % F != 0 or A != E * F:
print(f"[Error Occurred] {A} != {E} * {F}")
else:
print(f"{A} = {E} * {F}")
return 0
if __name__ == '__main__':
if A >= 2:
timer_start = timeit.default_timer()
factor(A)
timer_stop = timeit.default_timer()
running_time = round(timer_stop - timer_start, 6)
print("running time: ", running_time, " seconds")
else:
print("undefined for A<2")
In my computer, this made the running time to be decreased as around 3 seconds from about 4 seconds. So I concluded that the reason for the multiprocessing version code being slower is due to this part
else:
D += k * n + (k * (k + 1)) / 2
n += k
where the code is constantly interpreting what the argument is and translating it as an actual integer.
To avoid this, the easiest way to do is making a several code, when doing parallel computation on 4 cores, as follows.
else:
D += n + 1
n += 1
else:
D += 2*n + 3
n += 2
else:
D += 3*n + 6
n += 3
else:
D += 4*n + 10
n += 4
Among them, only the "n += 3" one will not give a desired output since it is not divisible by 4. (Recall that 4 is a divisor of n=21739276 from our original code)
If there are only 4 cases to test, then you can just make 4 copies of similar code by your hand.
However, let's think about this code
import timeit
import gmpy2
import math
A = gmpy2.mpz(1000007777)
# Input a positive integer to factor.
# Put it inside the parentheses as "A = gmpy2.mpz(....)"
def factor(A):
B = gmpy2.mpz(math.sqrt(2 * A + 0.25) - 1)
D = gmpy2.mpz(A - (B * B + B) / 2)
while (D > 0):
B += 1
D = gmpy2.mpz(A - (B * B + B) / 2)
n = gmpy2.mpz(0)
while (D != 0 and B <= A):
if (D > 0):
B += 1
D -= B
else:
D += 11299*n+63839350
n += 11299
if B > A:
return output(0, 0, 0)
else:
print(f"[B={B}, n={n}]")
if (B - n) % 2 == 0:
E = gmpy2.mpz((B - n) / 2)
F = gmpy2.mpz(B + n + 1)
else:
E = gmpy2.mpz(B - n)
F = gmpy2.mpz((B + n + 1) / 2)
return output(A, E, F)
def output(A, E, F):
if A == 0:
print(f"Initial Value Error: Reset the B value")
else:
if A % E != 0 or A % F != 0 or A != E * F:
print(f"[Error Occurred] {A} != {E} * {F}")
else:
print(f"{A} = {E} * {F}")
return 0
if __name__ == '__main__':
if A >= 2:
timer_start = timeit.default_timer()
factor(A)
timer_stop = timeit.default_timer()
running_time = round(timer_stop - timer_start, 6)
print("running time: ", running_time, " seconds")
else:
print("undefined for A<2")
Note that 11299 is a divisor of n=21739276. Indeed, this has decreased the running time of the code from around 2 seconds from 4 seconds.
If we do the same job with subtract part
if (D > 0):
B += 1
D -= B
I'm sure the code shall be faster but I haven't tried this yet.
So, why do we need to do this? That is, why do we need to make multiple version of similar codes to do a task of this algorithm, instead of directly replacing the arguments with the divisor of n?
It is because, we don't know the B and n value before we try it.
(If you find a method to know them don't tell me, just publish it on some decent journal)
Therefore, unless we figure out any pattern of B and n values to be identified, I believe the best method at current stage is to make multiple copies of similar code to be executed.
Here is the organized question,
Is there any way to replace the 'actual lines' inside a code by following the number of cores to be used?
For example, if there is a desired answer for the question, when there is a original code which include some lines of code as follows,
else:
D += n + 1
n += 1
and applying the method of desired answer shall result in copying the following codes
else:
D += 2*n + 3
n += 2
else:
D += 3*n + 6
n += 3
else:
D += 4*n + 10
n += 4
which do the same task, but only those lines of code have been replaced. If the number of code has been increased to 6, then we will have two more codes to be added that will concurrently executed for doing the task.
else:
D += 5*n + 15
n += 5
else:
D += 6*n + 21
n += 6
To repeat, the 'actual lines' of the code shall be replaced with another 'actual lines' since the following code
else:
D += k * n + (k * (k + 1)) / 2
n += k
is not that helpful for doing the exhaustive task, because of its job of interpreting what the actual argument of k is.
I've tried to be as specific as possible to describe my problem. If you need more elaboration please let me have a chance to elaborate the problem via comments and edits. Thank you.
What I've tried
I've tried to do the similar task at Java. Since Java is well known for OOP, and I thought OOP might be a promising way to solve this problem. However, the problem that Java has, it is not designed for arithmetic. I've tried the BigInteger library but it was extremely slow in my numerical test, even more than Python.
The other possible method could be doing some Scanf job by one's hand for the whole number of the sequence of code I'm going to use to. However, even assuming this method works, if the number of cores to be used increase as thousands then the method would not be considered as the best solution to this.
We've shown that
else:
D += 11299*n+63839350
n += 11299
this code works faster than the previous codes. However for a bigger argument of A, we might need more than thousands, maybe millions of multi-cores, to do the task efficiently.
So I have concluded this method is not the best shot that we can try, leaving aside whether it actually works.
Edit
I wanted to engage on discussion as much as I can. However, because of some unfriendly behavior at the comments, I may refrain myself from doing that. (Really appreciate the answer though)
This could be my last edit in this post. I just wanted to point out, the fact that 11299 is a divisor of n=21739276 doesn't mean that we can't try more than that.
Note that n = 21739276 = 19276 (mod 30000). Then, by replacing that part of the code as follows
n = gmpy2.mpz(19276)
D += gmpy2.mpz(n * (n + 1) / 2)
while (D != 0 and B <= A):
if (D > 0):
B += 1
D -= B
else:
D += 30000*n+450015000
n += 30000
I could reduce the running time from around 2.4seconds to 2.1seconds. I expect the running time can be reduced more if I manipulate this subtraction part,
if (D > 0):
B += 1
D -= B
but I haven't tried yet. All of these elements were the motivation behind that I thought I needed to know how to do the effective parallel computation. As I said, I may not engage on further discussion unless definitely required. If you are interested, you may feel free to test and modify this code without noticing me.
a needlessly long question, but this is python ... you can generate code at runtime if you write the function as a string, and replace the parts you need with numbers from arguments, you can exec the code exactly as you want, but this is not pythonic or fastest.
if your "hot loop" is limited by calculating things that can be known beforehand then it's best to just calculate them before the loop.
k_local = k # magic trick, bind the global k to a local variable k_local to make lookup faster
second_term = (k_local * (k_local + 1)) / 2
while (D != 0 and B <= A):
if (D > 0):
B += 1
D -= B
else:
D += k_local * n + second_term
n += k_local
this has the EXACT same performance as
else:
D += 11299*n+63839350
n += 11299
one thing i can recommend, is to make all variables local, (make k an argument), and use cython to compile your functions to C, this way the compiler overhead is partially removed, and if you really want better performance you can use gmpy's cython "bindings" to manipulate it on C level and remove the interpreter overhead entirely (not the ABI overhead though)
if you really want to go one step further, you can rewrite this in C++ and get more performance, as gmpy is originally a C package, and you will be removing the ABI overhead, do this if you really want to squeeze the last drop of performance out of it, as your "hot loop" is probably too hot for python's virtual machine, that's trying to simulate a computer inside a computer (same to be said for java VM), rewriting this in C++ can be as much as 50 times faster than your current implementation, but the gap can be made as small as only 5 times if you use the previous suggestions.

Creating a recursive function that removes odd digits of an integer

I just started working with recursive functions and I have to create a function that receives an integer and returns a new number that contains only the even digits. For example if it receives 23456, it should return 246. This is what I've tried:
def newInt(n):
dig = n % 10
if dig % 2 == 1:
return newInt(n//10)
elif dig % 2 == 0:
return str(n) + newInt(n//10)
print(newInt(32))
But I'm getting the following error:
RecursionError: maximum recursion depth exceeded in __instancecheck__
Any hints on what should I do to fix it?
You need a base case. There's also no need to convert any of the integers to strings. Here is a working version of newInt() that resolves both of these issues:
def newInt(n):
if not n:
return 0
dig = n % 10
if dig % 2 == 1:
return newInt(n // 10)
else:
return 10 * newInt(n // 10) + dig
Your issue is that you have no condition to stop recursion - every call to newInt results in another call. One way to stop would be to check if n is less than 10 and then just return n if it is even. For example:
def newInt(n):
if n < 10:
return n if n % 2 == 0 else 0
dig = n % 10
if dig % 2 == 1:
return newInt(n//10)
elif dig % 2 == 0:
return newInt(n//10) * 10 + dig
Note I have modified your function to return an integer rather than a string.
Here is a variant with divmod. Uncomment the print to see how it works:
def newInt(n):
d,r = divmod(n,10)
# print(n,d,r)
if d == 0:
return 0 if r%2 else r
if r % 2:
return newInt(d)
else:
return 10*newInt(d)+r
print(newInt(212033450))
Output: 22040
You don't even need to break out dig for each loop:
def newInt(n):
if n:
if n & 1:
return newInt(n // 10)
else:
return 10 * newInt(n // 10) + (n % 10)
return 0
This is a rewrite of #mozway's algortihm using Python 3.10 match..case syntax -
def newInt(n):
match divmod(n, 10):
case (0, r) if r & 1:
return 0
case (0, r):
return r
case (d, r) if r & 1:
return newInt(d)
case (d, r):
return 10 * newInt(d) + r
print(newInt(67120593306737201))
6200620
Note r & 1 is more efficient for testing if a number is even or odd. r % 2 performs division whereas & simply checks the first bit.

Python program gets stuck when dealing with large integers

I am working on a program that determines whether (2^n) - 1 (where n is an integer) is prime or not.
def check_prime(n):
if n == 1:
print("?")
global k
k = 0
for i in range(2, (n - 1)):
if n / i == n // i:
print("/")
k = 1
break
if k != 1:
print("p")
def special_prime(a):
b = (2 ** a) - 1
check_prime(b)
for i in range(1, 143):
print(i)
check_prime(i)
special_prime(i)
print("\n")
When it gets to i = 31, it just gets stuck. I was wondering if my algorithm is too slow or if there is something else that I am missing.

Dynamic programming for primitive calculator

I'm dealing with the problem, that is pretty similar to change coins problem.
I need to implement a simple calculator, that can perform the following three operations with the current number x: multiply x by 2, multiply x by 3, or add 1 to x.
Goal is given a positive integer n, find the minimum number of operations needed to obtain the number n starting from the number 1.
I made a greedy approach to that, bur it shows incorrect results
import sys
def optimal_sequence(n):
sequence = []
while n >= 1:
sequence.append(n)
if n % 3 == 0:
n = n // 3
elif n % 2 == 0:
n = n // 2
else:
n = n - 1
return reversed(sequence)
input = sys.stdin.read()
n = int(input)
sequence = list(optimal_sequence(n))
print(len(sequence) - 1)
for x in sequence:
print(x)
For example:
Input: 10
Output:
4
1 2 4 5 10
4 steps. But the correct one is 3 steps:
Output:
3
1 3 9 10
I read about dynamic programming, and hope I could implement it here. But, I can't get how to use it properly in particular case, can someone give me an advice?
Just solve it with a simple recursion and Memoization:
Code:
d = {}
def f(n):
if n == 1:
return 1, -1
if d.get(n) is not None:
return d[n]
ans = (f(n - 1)[0] + 1, n - 1)
if n % 2 == 0:
ret = f(n // 2)
if ans[0] > ret[0]:
ans = (ret[0] + 1, n // 2)
if n % 3 == 0:
ret = f(n // 3)
if ans[0] > ret[0]:
ans = (ret[0] + 1, n // 3)
d[n] = ans
return ans
def print_solution(n):
if f(n)[1] != -1:
print_solution(f(n)[1])
print n,
def solve(n):
print f(n)[0]
print_solution(n)
print ''
solve(10)
Hint: f(x) returns a tuple (a, b), which a denotes the minimum steps to get x from 1, and b denotes the previous number to get the optimum solution. b is only used for print the solution.
Output:
4 # solution for 10
1 3 9 10
7 # solution for 111
1 2 4 12 36 37 111
You may debug my code and to learn how it works. If you are beginner at DP, you could read my another SO post about DP to get a quick start.
Since Python can't recurse a lot (about 10000), I write an iterative version:
# only modified function print_solution(n) and solve(n)
def print_solution(n):
ans = []
while f(n)[1] != -1:
ans.append(n)
n = f(n)[1]
ans.append(1)
ans.reverse()
for x in ans:
print x,
def solve(n):
for i in range(1, n):
f(i)[0]
print_solution(n)
print ''
solve(96234) # 1 3 9 10 11 22 66 198 594 1782 5346 16038 16039 32078 96234

What's the problem of my prime test code?

I implemented the Miller-Rabin prime test algorithm found on wikipedia with Python 3.
It seems to be working correctly with most numbers but occasionaly fail on certain numbers.
For example, the prime number 99999999999999997 is judged to be NOT prime.
I implemented the algorithm line by line and I have no clue where the problem is.
Can any one help me ?
Here is my code.
the test input is:
1
99999999999999997
(No empty line between two lines.)
And the expected output should be YES, but it gives NO on my machine.
import random
def isPrime(n, k = 5):
'''
Primality test using Miller-Rabin method.
n The number to test primality.
k The number of M-R test to perform.
'''
if n == 1:
return False
if n == 2 or n == 3:
return True
if n % 2 == 0:
return False
# Calculate d
nn = n - 1
s = 1
while nn % (2 ** s) == 0:
s += 1
s -= 1
d = int(nn / (2 ** s))
for i in range(k):
a = random.randint(2, n - 1)
x = pow(a,d,n)
if x == 1 or x == n - 1:
continue
flag = True
for r in range(1, s):
x = pow(x,2,n)
if x == 1:
return False
if x == n - 1:
flag = False
break
if not flag:
continue
return False
return True
count = int(input())
for i in range(count):
if isPrime(int(input())):
print('YES')
else:
print('NO')
This is an implementation of Miller-Rabin I wrote a while ago. It has never given me an unexpected result -- though that doesn't mean it won't! It is substantially identical to the one you pasted, and it declares 99999999999999997 to be prime. Yours did too, when I tested it -- so that's a second to Mikola's opinion. But see below for one possible problem that I can't easily test... scratch that, I tested it, and it was the problem.
When it comes to primality testing, I'm no expert, but I spent a lot of time thinking about and coming to understand Miller-Rabin, and I'm pretty sure your implementation is spot-on.
def is_prime_candidate(self, p, iterations=7):
if p == 1 or p % 2 == 0: return False
elif p < 1: raise ValueError("is_prime_candidate: n must be a positive integer")
elif p < self.maxsmallprime: return p in self.smallprimes
odd = p - 1
count = 0
while odd % 2 == 0:
odd //= 2
count += 1
for i in range(iterations):
r = random.randrange(2, p - 2)
test = pow(r, odd, p)
if test == 1 or test == p - 1: continue
for j in range(count - 1):
test = pow(test, 2, p)
if test == 1: return False
if test == p - 1: break
else: return False
print i
return True
The one thing I noticed about your code that seemed off was this:
d = int(nn / (2 ** s))
Why int, I thought to myself. Then I realized you must be using Python 3. So that means you're doing floating point arithmetic here and then converting to int. That seemed iffy. So I tested it on ideone. And lo! the result was False. So I changed the code to use explicit floor division (d = nn // (2 ** s)). And lo! it was True.
I am going to reiterate my comment, since my testing seems to indicate your example is working. I strongly suspect that you just mistyped your test case. Maybe you can try taking a second look at it? Here is what I got from running it:
In [12]: millerrabin.isPrime(99999999999999997, 5)
Out[12]: True
EDIT: I just ran the updated version, and here is the output from the console:
1
99999999999999997
YES
Again, this looks correct.
From what I can see, the Miller-Rabin algorithm is only probabilistic. Were you not aware of this, or are you using a modified, non probabilistic version?

Categories