From a2c0e18b7d3db54feb44fcf14f2d7c92529a9f30 Mon Sep 17 00:00:00 2001 From: weilycoder Date: Sun, 16 Feb 2025 17:00:58 +0800 Subject: [PATCH 1/4] Add functions to find next and previous prime numbers, and generate random primes within a range --- cyaron/math.py | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/cyaron/math.py b/cyaron/math.py index dce3102..721c71b 100644 --- a/cyaron/math.py +++ b/cyaron/math.py @@ -549,3 +549,94 @@ def n2words(num: int, join: bool = True): if join: return ' '.join(words) return words + + +def nextprime(n: int): + """ + Find the next prime number after a given number. + Args: + n: The number after which to find the next prime. + Returns: + The next prime number after n. + """ + + if n < 2: + return 2 + if n == 2: + return 3 + if n % 6 == 0: + if miller_rabin(n + 1): + return n + 1 + n += 6 + elif 1 <= n % 6 < 5: + n += 6 - n % 6 + else: + if miller_rabin(n + 2): + return n + 2 + n += 7 + while True: + if miller_rabin(n - 1): + return n - 1 + if miller_rabin(n + 1): + return n + 1 + n += 6 + + +def prevprime(n: int, raise_error: bool = True): + """ + Find the previous prime number before a given number. + Args: + n: The number before which to find the previous prime. + raise_error: Raise an error if there is no prime number less than `n`. Default is True. + Returns: + The previous prime number before `n`. + Raises: + ValueError: If there is no prime number less than `n` and `raise_error` is True. + """ + if n <= 2: + if raise_error: + raise ValueError(f"No prime number less than {n}") + return 0 + if n == 3: + return 2 + if n <= 5: + return 3 + if n % 6 == 0: + if miller_rabin(n - 1): + return n - 1 + n -= 6 + elif n % 6 == 1: + if miller_rabin(n - 2): + return n - 2 + n -= 7 + else: + n -= n % 6 + while True: + if miller_rabin(n + 1): + return n + 1 + if miller_rabin(n - 1): + return n - 1 + n -= 6 + + +def randprime(a: int, b: int, raise_error: bool = True): + """ + Generate a random prime number in the range [a, b]. + Args: + a: The lower bound of the range. + b: The upper bound of the range. + Returns: + A random prime number in the specified range. + """ + st = random.randint(a, b) + if miller_rabin(st): + return st + nxt = nextprime(st) + if nxt <= b: + return nxt + pre = prevprime(st) + if pre >= a: + return pre + if raise_error: + raise ValueError(f"No prime number in the range [{a}, {b}]") + return 0 From 1229bdc845ad96101cb53384e100fa3ecccaa59c Mon Sep 17 00:00:00 2001 From: weilycoder Date: Sun, 16 Feb 2025 17:37:11 +0800 Subject: [PATCH 2/4] Modify the documentation --- cyaron/math.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cyaron/math.py b/cyaron/math.py index 721c71b..3f92d2f 100644 --- a/cyaron/math.py +++ b/cyaron/math.py @@ -25,6 +25,9 @@ miu(x): The MIU function of x dec2base(n,base): Number base conversion n2words(num,join=True): Number to words + nextprime(n): Find the next prime number after n + prevprime(n,raise_error=True): Find the previous prime number before n + randprime(a,b,raise_error=True): Generate a random prime number in the range [a,b] forked from https://blog.dreamshire.com/common-functions-routines-project-euler/ """ From e6343f9a897f9aa7b91c09e1f64df4f7c07653cc Mon Sep 17 00:00:00 2001 From: weilycoder Date: Sun, 16 Feb 2025 17:47:24 +0800 Subject: [PATCH 3/4] Add the test --- cyaron/tests/__init__.py | 1 + cyaron/tests/math_test.py | 46 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 cyaron/tests/math_test.py diff --git a/cyaron/tests/__init__.py b/cyaron/tests/__init__.py index 6fcff5c..38b6a40 100644 --- a/cyaron/tests/__init__.py +++ b/cyaron/tests/__init__.py @@ -6,3 +6,4 @@ from .graph_test import TestGraph from .vector_test import TestVector from .general_test import TestGeneral +from .math_test import TestMath diff --git a/cyaron/tests/math_test.py b/cyaron/tests/math_test.py new file mode 100644 index 0000000..3926a19 --- /dev/null +++ b/cyaron/tests/math_test.py @@ -0,0 +1,46 @@ +import unittest +from random import randint +from cyaron import randprime, nextprime, prevprime, prime_sieve + + +class TestMath(unittest.TestCase): + + def setUp(self): + self.prime_range = 100000 + self.prime_set = set(prime_sieve(self.prime_range * 2)) + return super().setUp() + + def test_randprime(self): + for _ in range(20): + self.assertTrue(randprime(1, self.prime_range) in self.prime_set) + + def test_nextprime(self): + + def bf_nextprime(n): + while True: + n += 1 + if n in self.prime_set: + return n + + for _ in range(20): + n = randint(1, self.prime_range) + self.assertEqual(nextprime(n), bf_nextprime(n)) + + def test_prevprime(self): + + def bf_prevprime(n): + while True: + n -= 1 + if n in self.prime_set: + return n + if n < 2: + return 0 + + for _ in range(20): + n = randint(1, self.prime_range) + self.assertEqual(prevprime(n, False), bf_prevprime(n)) + + self.assertRaises(ValueError, prevprime, 1) + self.assertRaises(ValueError, prevprime, 2) + self.assertEqual(prevprime(1, False), 0) + self.assertEqual(prevprime(2, False), 0) From 06cb3667c4dd2c3d0c96a5b79798d77678a2cd68 Mon Sep 17 00:00:00 2001 From: weilycoder Date: Sun, 16 Feb 2025 17:53:04 +0800 Subject: [PATCH 4/4] Enrich the test --- cyaron/tests/math_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cyaron/tests/math_test.py b/cyaron/tests/math_test.py index 3926a19..6381a5a 100644 --- a/cyaron/tests/math_test.py +++ b/cyaron/tests/math_test.py @@ -22,9 +22,10 @@ def bf_nextprime(n): if n in self.prime_set: return n - for _ in range(20): + for i in range(20): n = randint(1, self.prime_range) self.assertEqual(nextprime(n), bf_nextprime(n)) + self.assertEqual(nextprime(i), bf_nextprime(i)) def test_prevprime(self): @@ -36,11 +37,10 @@ def bf_prevprime(n): if n < 2: return 0 - for _ in range(20): + for i in range(20): n = randint(1, self.prime_range) self.assertEqual(prevprime(n, False), bf_prevprime(n)) + self.assertEqual(prevprime(i, False), bf_prevprime(i)) self.assertRaises(ValueError, prevprime, 1) self.assertRaises(ValueError, prevprime, 2) - self.assertEqual(prevprime(1, False), 0) - self.assertEqual(prevprime(2, False), 0)