I am trying to write a function to determine if a number is prime. I have come up with
the following solution, however inelegant, but cannot figure out how to write it.
I want to do the following: take the number x and divide it by every number that is less than itself. If any solution equals zero, print 'Not prime.' If no solution equals zero, print 'Prime.'
In other words, I want the function to do the following:
x % (x - 1) =
x % (x - 2) =
x % (x - 3) =
x % (x - 4) =
etc...
Here is as far as I have been able to get:
def prime_num(x):
p = x - 1
p = p - 1
L = (x % (p))
while p > 0:
return L
Wikipedia provides one possible primality check in Python
def is_prime(n):
if n <= 3:
return n >= 2
if n % 2 == 0 or n % 3 == 0:
return False
for i in range(5, int(n ** 0.5) + 1, 6):
if n % i == 0 or n % (i + 2) == 0:
return False
return True
Related
Here is my code:
import random
def miller(n, k):
"""
takes an integer n and evaluates whether it is a prime or a composite
n > 3, odd integer to be tested for primality
k, rounds of testing (the more tests, the more accurate the result)
"""
temp = n - 1 # used to find r and d in n = 2**d * r + 1, hence temporary
r = 0
while True:
if temp / 2 == type(int):
r += 1
else:
d = temp
break
temp = temp / 2
for _ in range(k):
a = random.SystemRandom().randrange(2, n - 2)
x = a**d % n
if x == 1 or x == n - 1:
continue
for _ in range(r - 1):
x = x**2 % n
if x == n - 1:
continue
return "Composite"
return "Probably prime"
Certainly there must be more effective ways to implement the algorithm in Python, so that it may handle large integers with ease?
Cheers
Find the sum of all multiples of n below m
Keep in Mind n and m are natural numbers (positive integers) m is
excluded from the multiples
sumMul(2, 9) ==> 2 + 4 + 6 + 8 = 20
sumMul(3, 13) ==> 3 + 6 + 9 + 12 = 30
sumMul(4, -7) ==> "INVALID"
I did sum of list using range(n, m, n) using n as step.
I also tried modulus to avoid range 3 args error.
I can pass many tests but cannot pass all of them.
I have tried lots of logic but to no avail. What I am doing wrong?
CODEWARS: https://www.codewars.com/kata/57241e0f440cd279b5000829/train/python
MY CODE:
def sum_mul(n, m):
my_list = [number for number in range(n, m) if number % n == 0]
sum_list = sum(my_list)
if sum_list >= 1:
return sum_list
elif n == 0 and m == 0:
return 'INVALID'
elif n == m:
return n - m
elif n > m:
return 'INVALID'
Your code fails if n == 0 as then the number % n checks in the list comprehension fail, so you should check that before trying to compute the sum. Also, you could use a range with step and just do sum(range(n, m, n)). However, both ways might be too slow for some test cases with very large m.
You can do this in O(1) with the following observations:
there are (m-1) // n multiples of n below m
the sum of natural numbers from 1 to n is n*(n+1)//2
Combine those two to get the result.
Example for sumMul(3, 13) ==> 3 + 6 + 9 + 12 = 30:
(13-1) // 3 == 4 so we know there are 4 multiples of 3 below 13
those are 3 + 6 + 9 + 12 == 3 * (1 + 2 + 3 + 4)
with (2) we know 1 + 2 + 3 + 4 == 4*5//2 == 10
so the result is 10 * 3 == 30
Putting that into code and handling the special cases is left as an exercise to the interested reader.
You have one main problem, that is you should prevent the situation when n==0 and you divide it in your list comprehension. It will raise zero division error. so you should check before the validation that n is not equal to zero.
Second thing is that you need to check whether n or m are negatives, as the exercise declared both n and m should be positives.
def sum_mul(n, m):
if n==0:
return 'INVALID'
my_list = [number for number in range(n, m) if number % n == 0]
sum_list = sum(my_list)
if sum_list >= 1:
return sum_list
elif n < 0 and m <= 0:
return 'INVALID'
elif n == m:
return n - m
elif n > m:
return 'INVALID'
You can just compute that result mathematically using integer divisions:
def sum_mul(n, m):
if n<1 or n>m: return "INVALID"
return m//n*(m//n+1)//2*n
First you get the number of multiple of n in m (which is merely dividing m by n ignoring the remainder) : m//n
Multiples of n will be nx1, nx2, nx3, ... up to the number of multiples. Factorizing the sum of those by n we get: n(1+2+3+ ... m//n).
The sum of numbers from 1 up to a given number x is obtained by x(x+1)/2. In this case x is the number of multiples m//n
Putting it all together we get n * x * (x+1) /2 where x is m//n, so:
n * (m//n) * (m // n + 1) // 2
You should comprove all cases before call sum function.
Like this:
def sum_mul(n, m):
if n == 0 or m == 0:
return 'INVALID'
if n == m:
return n - m
if n<0 or m<0:
return 'INVALID'
my_list = [number for number in range(n, m) if number % n == 0]
return sum(my_list)
In fact, you dont't need to create if elif structure because you are using returns, so next instruction after return not executed.
I ran into a problem: The code was very slow for 512 bit odd integers if you use classical division for (p-1)/2. But with floor division it works instantly. Is it caused by float conversion?
def solovayStrassen(p, iterations):
for i in range(iterations):
a = random.randint(2, p - 1)
if gcd(a, p) > 1:
return False
first = pow(a, int((p - 1) / 2), p)
j = (Jacobian(a, p) + p) % p
if first != j:
return False
return True
The full code
import random
from math import gcd
#Jacobian symbol
def Jacobian(a, n):
if (a == 0):
return 0
ans = 1
if (a < 0):
a = -a
if (n % 4 == 3):
ans = -ans
if (a == 1):
return ans
while (a):
if (a < 0):
a = -a
if (n % 4 == 3):
ans = -ans
while (a % 2 == 0):
a = a // 2
if (n % 8 == 3 or n % 8 == 5):
ans = -ans
a, n = n, a
if (a % 4 == 3 and n % 4 == 3):
ans = -ans
a = a % n
if (a > n // 2):
a = a - n
if (n == 1):
return ans
return 0
def solovayStrassen(p, iterations):
for i in range(iterations):
a = random.randint(2, p - 1)
if gcd(a, p) > 1:
return False
first = pow(a, int((p - 1) / 2), p)
j = (Jacobian(a, p) + p) % p
if first != j:
return False
return True
def findFirstPrime(n, k):
while True:
if solovayStrassen(n,k):
return n
n+=2
a = random.getrandbits(512)
if a%2==0:
a+=1
print(findFirstPrime(a,100))
As noted in comments, int((p - 1) / 2) can produce garbage if p is an integer with more than 53 bits. Only the first 53 bits of p-1 are retained when converting to float for the division.
>>> p = 123456789123456789123456789
>>> (p-1) // 2
61728394561728394561728394
>>> hex(_)
'0x330f7ef971d8cfbe022f8a'
>>> int((p-1) / 2)
61728394561728395668881408
>>> hex(_) # lots of trailing zeroes
'0x330f7ef971d8d000000000'
Of course the theory underlying the primality test relies on using exactly the infinitely precise value of (p-1)/2, not some approximation more-or-less good to only the first 53 most-significant bits.
As also noted in a comment, using garbage is likely to make this part return earlier, not later:
if first != j:
return False
So why is it much slower over all? Because findFirstPrime() has to call solovayStrassen() many more times to find garbage that passes by sheer blind luck.
To see this, change the code to show how often the loop is trying:
def findFirstPrime(n, k):
count = 0
while True:
count += 1
if count % 1000 == 0:
print(f"at count {count:,}")
if solovayStrassen(n,k):
return n, count
n+=2
Then add, e.g.,
random.seed(12)
at the start of the main program so you can get reproducible results.
Using floor (//) division, it runs fairly quickly, displaying
(6170518232878265099306454685234429219657996228748920426206889067017854517343512513954857500421232718472897893847571955479036221948870073830638539006377457, 906)
So it found a probable prime on the 906th try.
But with float (/) division, I never saw it succeed by blind luck:
at count 1,000
at count 2,000
at count 3,000
...
at count 1,000,000
Gave up then - "garbage in, garbage out".
One other thing to note, in passing: the + p in:
j = (Jacobian(a, p) + p) % p
has no effect on the value of j. Right? p % p is 0.
I am trying to write a program that will print all the primes within a given range. I have written it, the output is almost okay, it prints primes, but for some reason it prints 4, which is not a prime...
Any assistant will be most appreciated !
def primes():
start = int(input("Enter the starting number: "))
end = int(input("Enter the ending number: "))
num = 0
i = 0
ctr = 0
for num in range(start,end+1,1):
ctr = 0
for i in range(2,num//2,1):
if num % i == 0 :
ctr = ctr + 1
break
if (ctr==0 and num != 1):
print(num)
for i in range(2,num//2,1):
Lets check this snippet of code when num = 4,it becomes
for i in range(2,2,1):
Now we see the problem.
Solution..?
for i in range(2,(num//2)+1,1):
The following methods are all possible prime checkers you might use to check within your range:
def isPrime(Number): # slow
return 2 in [Number, 2 ** Number % Number]
def isprime(n): # out of memory errors with big numbers
"""check if integer n is a prime"""
# make sure n is a positive integer
n = abs(int(n))
# 0 and 1 are not primes
if n < 2:
return False
# 2 is the only even prime number
if n == 2:
return True
# all other even numbers are not primes
if not n & 1:
return False
# range starts with 3 and only needs to go up the squareroot of n
# for all odd numbers
for x in range(3, int(n ** 0.5) + 1, 2):
if n % x == 0:
return False
return True
def is_prime(n): # Best until now
if n == 2 or n == 3:
return True
if n < 2 or n % 2 == 0:
return False
if n < 9:
return True
if n % 3 == 0:
return False
r = int(n ** 0.5)
f = 5
while f <= r:
# print '\t', f
if n % f == 0:
return False
if n % (f + 2) == 0:
return False
f += 6
return True
for i in range(2,num//2,1):
Above line is wrong. You are iterating from 2 to num / 2 - 1.
You should iterate from 2 to sqrt(num). (range(2, int(math.sqrt(n)) + 1))
Alternatively you can do a special check for 2 and modify your range to range(3, int(math.sqrt(n) + 1, 2)
I'm trying to print all numbers in range 1-100 that are divisible by x and y (ie. 2 nad 3). For now i have
for x in range(0, 101):
if x % (2 and 3) == 0: print("2, 3: ", x)
elif x % 2 == 0: print("2: ", x)
elif x % 3 == 0: print("3: ", x)
But it is not accurate, any suggestions?
(2 and 3) evaluates to 3, that's why you never see the condition elif x % 3 == 0 being executed, notice there's no print("3: ", x) in the output of your code, because it'd already fallen into the condition if x % (2 and 3) == 0.
You should be better using if ((x % 2) == 0 and (x % 3) == 0) : print("2, 3: ", x) on that line.
The reason it is not accurate is by writing x % (2 and 3) python is interpreting (2 and 3).(https://docs.python.org/2/reference/expressions.html)
in python (2 and 3) would return 3 because both values are "truthy" and the AND comparison operator in python will return the last value when both items are True.
As per Rajesh Kumar's suggestion you could do
if x % 6 == 0: # ...
or
if x % 2 == 0 and x % 3 == 0: # More verbose...
If you have a number that hast to be dividable by number x and number y you can look at it like:
If some rest is left after a division with divisor x or divisor y, the currently considered number toDivide is not the number you are looking for, because you want numbers where neither of the devisions results in a rest.
x = 2
y = 3
for toDivide in range(1, 101):
# can't divide by x and y
if toDivide%x and toDivide%y:
continue
print((str(x)+", "+str(y) if not toDivide%x and not toDivide%y else (str(x) if not toDivide%x else str(y)))+":"+str(toDivide))
edit: found and resolved the code-error
In if x % (2 and 3) == 0 the value of (2 and 3) is evaluated first, you should first check divisibility by 2 then by 3. i.e.
if (x % 2) and (x % 3)
the two expressions in brackets return booleans that you finally evaluate using and.
corrected:
for x in range(0, 101):
if (x % 2) and (x % 3):
print("2, 3: ", x)
elif x % 2 == 0:
print("2: ", x)
elif x % 3 == 0:
print("3: ", x)