From bf3732794abc17096337d1a01e78334688b85f40 Mon Sep 17 00:00:00 2001 From: felixm Date: Sun, 1 Oct 2023 18:10:27 +0200 Subject: [PATCH] Add own bitarray and Miller-Rabin primality test. --- python/lib_bitarray.py | 39 +++++++++++++++++++++++++++++++++++++++ python/lib_prime.py | 32 ++++++++++++++++++++++++++------ 2 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 python/lib_bitarray.py diff --git a/python/lib_bitarray.py b/python/lib_bitarray.py new file mode 100644 index 0000000..b153e64 --- /dev/null +++ b/python/lib_bitarray.py @@ -0,0 +1,39 @@ +class Bitarray: + def __init__(self, num_bits): + self.word_size = 32 + self.word_mask = 2**self.word_size - 1 + num_words = num_bits // self.word_size + if num_bits % self.word_size != 0: + num_words += 1 + self.num_bits = num_bits + self.num_words = num_words + self.array = [0] * num_words + + def setall(self, target: bool): + if target: + self.array = [self.word_mask] * self.num_words + else: + self.array = [0] * self.num_words + + def set(self, bit, target: bool): + assert(bit < self.num_bits) + word_index = bit // self.word_size + bit_index = bit % self.word_size + value = self.array[word_index] + if target: + value = (value | (1 << bit_index)) + else: + value = (value & (~(1 << bit_index))) + self.array[word_index] = value + + def get(self, bit) -> bool: + assert(bit < self.num_bits) + word_index = bit // self.word_size + bit_index = bit % self.word_size + return bool(self.array[word_index] & (1 << bit_index)) + + def __getitem__(self, bit: int) -> bool: + return self.get(bit) + + def __setitem__(self, bit: int, value: bool): + self.set(bit, value) diff --git a/python/lib_prime.py b/python/lib_prime.py index 1cb33db..4d194c4 100644 --- a/python/lib_prime.py +++ b/python/lib_prime.py @@ -1,4 +1,5 @@ from functools import lru_cache +from lib_bitarray import Bitarray try: from lib_misc import get_item_counts from lib_misc import product @@ -65,6 +66,29 @@ def is_prime(n): return True +def is_prime_rabin_miller(number): + """ Rabin-Miller Primality Test """ + if number % 6 not in [1,5]: + return False + + r, s = 1, number - 1 + while s % 2 == 0: + s //= 2 + r += 1 + + for witness in [2, 3, 5, 7, 11, 13, 17, 23, 29, 31, 37, 41, 43, 47, 53]: + remainder = pow(witness, s, number) + if remainder == 1: + continue + for _ in range(1, r): + if remainder == number - 1: + break + remainder = pow(remainder, 2, number) + else: + return False + return True + + def prime_nth(n): """Returns the nth prime number. The first number is 1 indexed, i.e. n = 1 -> 2, n = 2 -> 3, etc. @@ -97,12 +121,8 @@ def primes(n_max): :param n_max: """ - try: - import bitarray - b = bitarray.bitarray(n_max) - b.setall(True) - except ModuleNotFoundError: - b = [True for _ in range(n_max)] + b = Bitarray(n_max) + b.setall(True) n = 1 b[n - 1] = False while n * n <= n_max: