def erat(n): """Return a list of primes up to and including n. This is a fixed-size version of the Sieve of Eratosthenes, using an adaptation of the traditional algorithm. >>> erat(30) [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] """ if n < 2: return [] # Generate a fixed array of integers. arr = list(range(n+1)) # A list is faster than an array. # Cross out 0 and 1 since they aren't prime. arr[0] = arr[1] = None i = 2 while i*i <= n: # Cross out all the multiples of i starting from i**2. for p in range(i*i, n+1, i): arr[p] = None # Advance to the next number not crossed off. i += 1 while i <= n and arr[i] is None: i += 1 return list(filter(None, arr))
def erat(n): """Return a list of primes up to and including n. This is a fixed-size version of the Sieve of Eratosthenes, using an adaptation of the traditional algorithm. >>> erat(30) [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] """ if n < 2: return [] # Generate a fixed array of integers. arr = list(range(n + 1)) # A list is faster than an array. # Cross out 0 and 1 since they aren't prime. arr[0] = arr[1] = None i = 2 while i * i <= n: # Cross out all the multiples of i starting from i**2. for p in range(i * i, n + 1, i): arr[p] = None # Advance to the next number not crossed off. i += 1 while i <= n and arr[i] is None: i += 1 return list(filter(None, arr))
def test_range(self): range = compat23.range self.assertEqual(list(range(5)), [0, 1, 2, 3, 4]) self.assertEqual(list(range(5, 10)), [5, 6, 7, 8, 9]) self.assertEqual(list(range(5, 15, 3)), [5, 8, 11, 14]) if sys.version_info[0] < 3: self.assertTrue(range is xrange)
def test_with_composites_with_bases(self): # Composites should return 0 or 2 but never 1. isprime = self.get_primality_test() errmsg = "%d detected as definitely prime with %r" for _ in range(10): factors = PRIMES[51:] * 3 random.shuffle(factors) n = product(factors[:8]) bases = tuple([random.randint(2, n - 1) for _ in range(5)]) self.assertTrue(isprime(n, bases) != 1, errmsg % (n, bases))
def test_with_composites_with_bases(self): # Composites should return 0 or 2 but never 1. isprime = self.get_primality_test() errmsg = "%d detected as definitely prime with %r" for _ in range(10): factors = PRIMES[51:]*3 random.shuffle(factors) n = product(factors[:8]) bases = tuple([random.randint(2, n-1) for _ in range(5)]) self.assertTrue(isprime(n, bases) != 1, errmsg % (n, bases))
def test_composites_with_known_liars(self): # These values have come from this email: # https://gmplib.org/list-archives/gmp-discuss/2005-May/001652.html isprime = self.get_primality_test() N = 1502401849747176241 # Composite, but 2 through 11 are all M-R liars. # Lowest witness is 12. self.assertEqual(isprime(N, tuple(range(2, 12))), 2) self.assertEqual(isprime(N, 12), 0) N = 341550071728321 # Composite, but 2 through 22 are all M-R liars. # Lowest witness is 23. self.assertEqual(isprime(N, tuple(range(2, 23))), 2) self.assertEqual(isprime(N, 23), 0)
def primes0(): """Generate prime numbers by trial division extremely slowly. >>> p = primes0() >>> [next(p) for _ in range(10)] [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] This is about as naive an implementation of trial division as you can get. Not even the most obvious and trivial optimizations are used: - it uses all numbers as potential primes, whether odd or even, instead of skipping even numbers; - it checks for primality by dividing against every number less than the candidate, instead of stopping early; - even when it finds a factor, it stupidly keeps on going. """ i = 2 yield i while True: i += 1 composite = False for p in range(2, i): if i%p == 0: composite = True if not composite: # It must be a prime. yield i
def test_factors_random(self): # Test the factors.factorise function with a random number. numfactors = random.randint(1, 8) values = [random.choice(PRIMES) for _ in range(numfactors)] values.sort() n = product(values) self.assertEqual(factors.factorise(n), values)
def test_prime_sum(self): # Test the prime_sum function by comparing it to prime_partial_sums. it = pyprimes.prime_partial_sums() for i in range(100): expected = next(it) actual = pyprimes.prime_sum(i) self.assertEqual(actual, expected)
def test_primes_start(self): # Test the prime generator with start argument only. expected = [211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293] assert len(expected) == 16 it = pyprimes.primes(200) values = [next(it) for _ in range(16)] self.assertEqual(values, expected)
def test_with_composites(self): # Composites should return 0 or 2 but never 1. isprime = self.get_primality_test() for _ in range(10): factors = self.get_factors() n = product(factors) self.assertTrue(isprime(n) != 1, "composite %d detected as definitely prime" % n)
def test_primes_are_not_nonprime_with_bases(self): # Since there are no false negatives, primes will never test as # composite, no matter what bases are used. isprime = self.get_primality_test() for p in PRIMES[1:]: # Skip prime 2. bases = list(range(1, p)) random.shuffle(bases) bases = tuple(bases[:10]) self.assertEqual(isprime(p, bases), 2)
def test_moderate_composites(self): # Test is_probable_prime with moderate-sized composites. for i in range(10): # We should not run out of primes here. If we do, it's a bug # in the test. p, q = next(self.primes), next(self.primes) n = p*q assert n < 2**60, "n not in deterministic range for i_p_p" self.assertEqual(probabilistic.is_probable_prime(n), 0)
def test_with_composites(self): # Composites should return 0 or 2 but never 1. isprime = self.get_primality_test() for _ in range(10): factors = self.get_factors() n = product(factors) self.assertTrue( isprime(n) != 1, "composite %d detected as definitely prime" % n)
def test_moderate_composites(self): # Test is_probable_prime with moderate-sized composites. for i in range(10): # We should not run out of primes here. If we do, it's a bug # in the test. p, q = next(self.primes), next(self.primes) n = p * q assert n < 2**60, "n not in deterministic range for i_p_p" self.assertEqual(probabilistic.is_probable_prime(n), 0)
def test_primes_start(self): # Test the prime generator with start argument only. expected = [ 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293 ] assert len(expected) == 16 it = pyprimes.primes(200) values = [next(it) for _ in range(16)] self.assertEqual(values, expected)
def test_prime_partial_sums(self): it = pyprimes.prime_partial_sums() self.assertTrue(it is iter(it)) # Table of values from http://oeis.org/A007504 expected = [ 0, 2, 5, 10, 17, 28, 41, 58, 77, 100, 129, 160, 197, 238, 281, 328, 381, 440, 501, 568, 639, 712, 791, 874, 963, 1060, 1161, 1264, 1371, 1480, 1593, 1720, 1851, 1988, 2127, 2276, 2427, 2584, 2747, 2914, 3087, 3266, 3447, 3638, 3831, 4028, 4227, 4438, 4661, 4888 ] actual = [next(it) for _ in range(len(expected))] self.assertEqual(actual, expected)
def test_prime_partial_sums(self): it = pyprimes.prime_partial_sums() self.assertTrue(it is iter(it)) # Table of values from http://oeis.org/A007504 expected = [ 0, 2, 5, 10, 17, 28, 41, 58, 77, 100, 129, 160, 197, 238, 281, 328, 381, 440, 501, 568, 639, 712, 791, 874, 963, 1060, 1161, 1264, 1371, 1480, 1593, 1720, 1851, 1988, 2127, 2276, 2427, 2584, 2747, 2914, 3087, 3266, 3447, 3638, 3831, 4028, 4227, 4438, 4661, 4888] actual = [next(it) for _ in range(len(expected))] self.assertEqual(actual, expected)
def primes1(): """Generate prime numbers by trial division very slowly. >>> p = primes1() >>> [next(p) for _ in range(10)] [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] This adds a single optimization to ``primes0``, using a short-circuit test for primality: as soon as a factor is found, the candidate is rejected immediately. """ i = 2 yield i while True: i += 1 if all(i%p != 0 for p in range(2, i)): yield i
def primes2(): """Generate prime numbers by trial division very slowly. >>> p = primes2() >>> [next(p) for _ in range(10)] [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] This is an incremental improvement over ``primes1`` by only testing odd numbers as potential primes and factors. """ yield 2 i = 3 yield i while True: i += 2 if all(i%p != 0 for p in range(3, i, 2)): yield i
def primes3(): """Generate prime numbers by trial division slowly. >>> p = primes3() >>> [next(p) for _ in range(10)] [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] This is an incremental improvement over ``primes2`` by only testing potential factors up to the square root of the candidate. For small primes below 50000 or so, this may be slightly faster than ``primes4``. """ yield 2 i = 3 yield i while True: i += 2 if all(i%p != 0 for p in range(3, isqrt(i)+1, 2)): yield i
def isprime(n): """Naive primality test using naive and unoptimized trial division. >>> isprime(17) True >>> isprime(18) False Naive, slow but thorough test for primality using unoptimized trial division. This function does far too much work, and consequently is very slow. Nevertheless, it is guaranteed to give the right answer. Eventually. """ if n == 2: return True if n < 2 or n % 2 == 0: return False for i in range(3, isqrt(n)+1, 2): if n % i == 0: return False return True
def check_against_known_prime_list(self, prime_maker): """Check that generator produces the first 100 primes.""" it = prime_maker() primes = [next(it) for _ in range(100)] self.assertEqual(primes, PRIMES)
def test_below_two_are_nonprime_with_bases(self): # Test that values of n below 2 are non-prime. isprime = self.get_primality_test() for n in range(-7, 2): self.assertEqual(isprime(n, 4), 0) self.assertEqual(isprime(n, (3, 5)), 0)
def test_erat(self): for i in range(2, 544): self.assertEqual(sieves.erat(i), self.primes_below(i))
def test_factors_negative(self): # Test the factors.factorise function with negative values. f = factors.factorise for n in range(40, 50): assert n != -1 self.assertEqual(f(-n), [-1] + f(n))
def check_composites_are_not_prime(self, prime_checker): """Check that composites are not detected as prime.""" composites = set(range(-100, max(PRIMES)+1)) - set(PRIMES) for n in composites: self.assertFalse(prime_checker(n))
def check_composites_are_not_prime(self, prime_checker): """Check that composites are not detected as prime.""" composites = set(range(-100, max(PRIMES) + 1)) - set(PRIMES) for n in composites: self.assertFalse(prime_checker(n))