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?
Related
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.
I tried to write my own power() function in python but when i compared it with python inbuilt pow() function in output and speed. I found that my code is 6-7 times slower and last 3-4 digits of output is different as compared to output of inbuilt pow() function for floating point numbers. I am totally new to python and unable to find the explanation. plz help
Note:- I have used binomial expansion for calculating fractional power and Binary Exponent for integral power
Here is my code-
def power(x, n):
if not(isinstance(x, complex) or isinstance(n, complex)):
res = 1
if n == 0 and x != 0:
return 1
if n > 0 and x == 0:
return 0
if n < 0 and x == 0:
return "Zero Division Error"
if n == 0 and x == 0:
return "Indeterminate Form"
if n == 1:
return x
if n > 0 and n < 1:
return fpower(x,n)
if n > 1 and n < 2:
return x*fpower(x,n-1)
if n == -1:
return 1/x
if n < 0 and n > -1:
return fpower(x,n)
if n < -1 and n > -2:
return 1/x*fpower(x,n+1)
if n >= 2:
f_p = n - n // 1
t_x = x
n //= 1
if n%2:
res = x
n //= 2
else:
res = 1
n //= 2
while n != 1 and n > 1:
if n%2:
res *= x*x
x *= x
n //= 2
res *= x*x
if f_p == 0:
return res
elif f_p < 1:
return res*fpower(t_x,f_p)
if n <= -2:
f_p = n+(-n // 1)
t_x = x
n = -n // 1
if n%2:
res = 1/x
n = n // 2
else:
res = 1
n = n // 2
while n != 1 and n > 1:
if n%2:
res *= 1/x*1/x
x *= x
n //= 2
res *= 1/x*1/x
if f_p == 0:
return res
elif f_p > -1:
return res*fpower(t_x,f_p)
#function to calculate fractional power
def fpower(x, n):
pwr = 0
sign = 1
t_n = n
if x < 0:
x *= -1
sign = -1
while x > 2:
x = x/2
pwr += 1
if x >1:
pwr *= n
n *= -1
x = 1/x-1
elif x < 0.5 and x != 0:
x = sign*1/x
return fpower(x,-n)
elif x != 0:
x -= 1
res = 0
step = 1
coeff = 1
i = 0
while step > 1e-20:
step = coeff*power(x,i)
res += step
coeff *= (n-i)/(i+1)
i += 1
if step < 0:
step *= -1
mp = res*power(2,pwr)
if sign < 0:
pi = 3.141592653589793
real = mp*cos(t_n*pi)
img = mp*sin(t_n*pi)
if img != 0:
return complex(real,img)
else:
return real
else:
return mp
Output Comparison:
Inbuilt fn -
pow(89,99.354)
4.7829376579139805e+193
Own fn -
power(89,99.354)
4.7829376579139765e+193
Speed Comparison:
Inbuilt fn time -
pow(89,99.354)
0.00026869773864746094
Own fn time-
power(89,99.354)
0.0023398399353027344
There are a few things that can be said here. First of all, many Python standard library functions will be implemented in C, not in Python, so they will be faster. This makes sense, as the standard library will be called by a lot of code lots of times, so it pays off to implement such often-used code in a faster language.
Along with that goes additional optimization: this code is called so often that, besides implementing it in C, it makes sense to optimize this code. Compared to baseline Python, this includes writing "faster" C, but also what you get out of the box from your C compiler.
Some cursory research doesn't suggest this is the case, but exponentiation, as a common math operation, could also have some hardware acceleration that requires you to use specific intructions of the architecture you're running on - which you won't easily (if at all) be able to utilize in pure Python.
Then there's the matter of algorithms; once we leave the language difference aside, there are different ways to compute exponentiation, and without contrary evidence you should not assume that you have chosen the most efficient one. From you pointing out your algorithms it seems you have carefully chosen which ones to use, but still - when you're posing aquestion like this, don't simply assume you made an equally good choice as the standard library of a *looks at Wikipedia* 30 year old language.
Finally, don't forget that benchmarking methodology also plays a role in questions like this in general. a 6-7 times difference won't go away by changing your methodology, but it's worth remembering that testing your code against a very small number of inputs may not be representative of your code's performance in general, and different inputs will be representative for the built-in pow.
That's my thoughts on performance; as for accuracy, floating point errors can simply add up. As soon as you perform more than one operation on a decimal number, this will happen. (And remember, in general the first operation is representing the number in binary (IEEE 754) floating point format.) Wikipedia gives the example if squaring 0.1; 0.1 can not be represented precisely in binary, so you get your first rounding error here. As a result, squaring it will give you a less precise result than the best approximation for 0.01. As far as I can tell, you're not trying to comensate for roundign errors, and you're using a loop, so noticeable rounding errors are inevitable.
I have written a code of Wilson prime numbers and my code is working for most of the numbers but it's giving OverflowError: int too large to convert to float for very large numbers. Is there any way to write Wilson prime number code for very large numbers.
The main problem is for checking Wilson prime Wilson primes it should satisfy the following condition. Where P represents a prime number.
Then ((P-1)! + 1) / (P * P) should give a whole number.
And as you can see factorials are involved in this procedure, so for very large numbers it's pretty difficult.
My Code :
def am_i_wilson(n):
import math
n1 = math.sqrt(n)
n1 = math.ceil(n1)
c = 0
def fact(n):
num = 1
for i in range(2,n+1):
num = num*i
return num
if n <= 1:
return False
for i in range(2, n1 + 1):
if n%i == 0:
c+ = 1
if c != 0:
return False
x = (fact(n-1)+1)/((n**2)*1.0)
return x.is_integer()
In my code, I am returning True if the number is Wilson Prime else False. Here n is the number to check if it's Wilson prime or not.
I think this is the most efficient way
import math
def am_i_wilson(num):
if num < 2 or not all(n % i for i in range(2, num)):
return False
return (math.factorial(num - 1) + 1) % (num ** 2) == 0
or you can try this too
import math
def am_i_wilson(n):
if n <= 2:
return False
fact=math.factorial(n-1)
#this conditional checks that the number is prime or not
#this condition is called wilson theorem in number theory
if (fact+1)%n==0:
x = (fact+1)%(n**2)
if x==0:
return True
else:
return False
else:
return False
if anyone has any better method then please answer it.
Your program primarily relies on testing for primes and computing factorials. You separate out the factorial logic but embed an inefficient prime test -- it keeps testing remainders after it knows the number isn't prime! I would separate both out so that they can be tested and optimized independently of the Wilson prime test itself:
def factorial(n):
number = 1
for i in range(2, n + 1):
number *= i
return number
def am_i_prime(n):
if n < 2:
return False
if n % 2 == 0:
return n == 2
for divisor in range(3, int(n ** 0.5) + 1, 2):
if n % divisor == 0:
return False
return True
def am_i_wilson(n):
return am_i_prime(n) and (factorial(n - 1) + 1) % n ** 2 == 0
A more efficient approach, given a fixed target to test up to, would be to implement a prime sieve and for each prime encountered, while you're computing the sieve, test if it's a Wilson prime.
I've been experimenting with prime sieves recently. I did a quick modification (i.e. hack) to one of them written by Robert William Hanks and came up with this. Output first:
$ ./wilson_primes.py 10000
[5, 13, 563]
...so I suspect the Wikipedia article about Wilson primes is correct ;-)
import sys
def fact(n):
num = 1
for i in range(2, n+1):
num *= i
return num
def is_wilson(n):
return (fact(n-1)+1) % n**2 == 0
def rwh_primes1(n):
""" Returns a list of primes < n """
sieve = [True] * (n/2)
for i in range(3,int(n**0.5)+1,2):
if sieve[i/2]:
sieve[i*i/2::i] = [False] * ((n-i*i-1)/(2*i)+1)
# return [2] + [2*i+1 for i in xrange(1,n/2) if sieve[i]]
for i in range(1,n/2):
if sieve[i]:
p = 2*i + 1 # convert index to normal prime
if is_wilson(p): #
yield p #
if len(sys.argv) > 1:
N = int(float(sys.argv[1]))
else:
N = 10000 # default: 1e4 10,000
print [p for p in rwh_primes1(N)]
First I tried just the fact() function and was pleasantly surprised to see it can produce huge results. But it is very slow compared to the original prime sieve. Perhaps it could be made to run faster by remembering the last factorial computed and re-use that to skip part of next factorial computation.
EDIT
I changed fact() to remember its last result, as follows:
last_fact = 1
last_n = 1
def fact2(n):
global last_fact, last_n
num = last_fact
for i in range(last_n+1, n+1):
num *= i
last_n = n
last_fact = num
return num
def is_wilson(n):
return (fact2(n-1)+1) % n**2 == 0
That did speed it up quite a bit. cProfile shows that is_wilson() is now the bottleneck. I can't think of an easy way to make it faster.
This question already has answers here:
Fast prime factorization module
(7 answers)
Closed 5 years ago.
I'm trying to get a fast way to determine if a number is prime using Python.
I have two functions to do this. Both return either True or False.
Function isPrime1 is very fast to return False is a number is not a prime. For example with a big number. But it is slow in testing True for big prime numbers.
Function isPrime2 is faster in returning True for prime numbers. But if a number is big and it is not prime, it takes too long to return a value. First function works better with that.
How can I come up with a solution that could quickly return False for a big number that is not prime and would work fast with a big number that is prime?
def isPrime1(number): #Works well with big numbers that are not prime
state = True
if number <= 0:
state = False
return state
else:
for i in range(2,number):
if number % i == 0:
state = False
break
return state
def isPrime2(number): #Works well with big numbers that are prime
d = 2
while d*d <= number:
while (number % d) == 0:
number //= d
d += 1
if number > 1:
return True
else:
return False`
Exhaustive division until the square root is about the simplest you can think of. Its worst case is for primes, as all divisions must be performed. Anyway, until a billion, there is virtually no measurable time (about 1.2 ms for 1000000007).
def FirstPrimeFactor(n):
if n & 1 == 0:
return 2
d= 3
while d * d <= n:
if n % d == 0:
return d
d= d + 2
return n
Note that this version returns the smallest divisor rather than a boolean.
Some micro-optimizations are possible (such as using a table of increments), but I don' think they can yield large gains.
There are much more sophisticated and faster methods available, but I am not sure they are worth the fuss for such small n.
Primality tests is a very tricky topic.
Before attempting to speed up your code, try to make sure it works as intended.
I suggest you start out with very simple algorithms, then build from there.
Of interest, isPrime2 is flawed. It returns True for 6, 10, 12, ...
lines 3 to 6 are very telling
while d*d <= number:
while (number % d) == 0:
number //= d
d += 1
When a factor of number d is found, number is updated to number = number // d and at the end of the while loop, if number > 1 you return True
Working through the code with number = 6:
isPrime2(6)
initialise> number := 6
initialise> d := 2
line3> check (2 * 2 < 6) :True
line4> check (6 % 2 == 0) :True
line5> update (number := 6//2) -> number = 3
line6> update (d : d + 1) -> d = 3
jump to line3
line3> check (3 * 3 < 3) :False -> GOTO line7
line7> check(number > 1) -> check(3 > 1) :True
line8> return True -> 6 is prime
Here is what I came up with
def is_prime(number):
# if number is equal to or less than 1, return False
if number <= 1:
return False
for x in range(2, number):
# if number is divisble by x, return False
if not number % x:
return False
return True
This is my solution to the Project Euler Problem 3:
def max_prime(x):
for i in range(2,x+1):
if x%i == 0:
a = i
x = x/i
return a
max_prime(600851475143)
It takes too much time to run. What's the problem?
There are several problems with your code:
If you're using Python 3.x, use // for integer division instead of / (which will return a float).
You solution doesn't account for the multiplicity of the prime factor. Take 24, whose factorization is 2*2*2*3. You need to divide x by 2 three times before trying the next number.
You don't need to try all the values up to the initial value of x. You can stop once x has reached 1 (you know you have reached the highest divisor at this point).
Once you solve these three problems, your solution will work fine.
==> projecteuler3.py
import eulerlib
def compute():
n = 600851475143
while True:
p = smallest_prime_factor(n)
if p < n:
n //= p
else:
return str(n)
# Returns the smallest factor of n, which is in the range [2, n]. The result is always prime.
def smallest_prime_factor(n):
assert n >= 2
for i in range(2, eulerlib.sqrt(n) + 1):
if n % i == 0:
return i
return n # n itself is prime
if __name__ == "__main__":
print(compute())
Your solution is trying to iterate up to 600851475143, which isn't necessary. You only need to iterate up to the square root of the largest prime factor.
from math import sqrt
def max_prime_factor(x):
i = 2
while i ** 2 <= x:
while x % i == 0: # factor out ALL multiples of i
x //= i
i += 1
return x
print(max_prime_factor(600851475143))