From 0c5ef1f0820d8c752f859e07b4662bb088d4e915 Mon Sep 17 00:00:00 2001 From: lighting9999 Date: Fri, 19 Sep 2025 21:43:07 +0800 Subject: [PATCH 1/5] Optimize perfect cube detection for large numbers with modular checks and improved boundary estimation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Added modular arithmetic checks to quickly eliminate numbers that cannot be perfect cubes: · Last digit check: Only digits 0-9 can be cube endings · Modulo 7 check: Cubes can only be 0, 1, or 6 mod 7 · Modulo 9 check: Cubes can only be 0, 1, or 8 mod 9 2. Improved boundary estimation for very large numbers (n > 10^18): · Uses logarithmic approximation to calculate a reasonable upper bound · Reduces the binary search space significantly for extremely large values 3. Optimized computation in the binary search loop: · Added a check to avoid expensive cubic calculations for very large mid values · Uses integer division to prevent overflow in comparisons 4. Enhanced test coverage with comprehensive doctests: · Added tests for very large numbers (up to 10^300) · Included edge cases and error conditions · Maintained compatibility with existing tests --- maths/perfect_cube.py | 115 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 106 insertions(+), 9 deletions(-) diff --git a/maths/perfect_cube.py b/maths/perfect_cube.py index a732b7cce6c8..161231fb9224 100644 --- a/maths/perfect_cube.py +++ b/maths/perfect_cube.py @@ -1,14 +1,43 @@ def perfect_cube(n: int) -> bool: """ Check if a number is a perfect cube or not. - + + Note: This method uses floating point arithmetic which may be + imprecise for very large numbers. + >>> perfect_cube(27) True + >>> perfect_cube(64) + True >>> perfect_cube(4) False + >>> perfect_cube(0) + True + >>> perfect_cube(1) + True + >>> perfect_cube(-8) # Negative perfect cube + True + >>> perfect_cube(-9) # Negative non-perfect cube + False + >>> perfect_cube(10**6) # Large perfect cube (100^3) + True + >>> perfect_cube(10**6 + 1) # Large non-perfect cube + False """ + # Handle negative numbers + if n < 0: + n = -n + is_negative = True + else: + is_negative = False + val = n ** (1 / 3) - return (val * val * val) == n + # Round to avoid floating point precision issues + rounded_val = round(val) + result = rounded_val * rounded_val * rounded_val == n + + # For negative numbers, we need to check if the cube root would be negative + return result and not (is_negative and rounded_val == 0) def perfect_cube_binary_search(n: int) -> bool: @@ -16,13 +45,33 @@ def perfect_cube_binary_search(n: int) -> bool: Check if a number is a perfect cube or not using binary search. Time complexity : O(Log(n)) Space complexity: O(1) - + >>> perfect_cube_binary_search(27) True >>> perfect_cube_binary_search(64) True >>> perfect_cube_binary_search(4) False + >>> perfect_cube_binary_search(0) + True + >>> perfect_cube_binary_search(1) + True + >>> perfect_cube_binary_search(-8) # Negative perfect cube + True + >>> perfect_cube_binary_search(-9) # Negative non-perfect cube + False + >>> perfect_cube_binary_search(10**6) # Large perfect cube (100^3) + True + >>> perfect_cube_binary_search(10**6 + 1) # Large non-perfect cube + False + >>> perfect_cube_binary_search(10**18) # Very large perfect cube (10^6)^3 + True + >>> perfect_cube_binary_search(10**18 + 1) # Very large non-perfect cube + False + >>> perfect_cube_binary_search(10**100) # Extremely large number + False + >>> perfect_cube_binary_search(10**300) # Extremely large number + False >>> perfect_cube_binary_search("a") Traceback (most recent call last): ... @@ -31,25 +80,73 @@ def perfect_cube_binary_search(n: int) -> bool: Traceback (most recent call last): ... TypeError: perfect_cube_binary_search() only accepts integers + >>> perfect_cube_binary_search(None) + Traceback (most recent call last): + ... + TypeError: perfect_cube_binary_search() only accepts integers + >>> perfect_cube_binary_search([]) + Traceback (most recent call last): + ... + TypeError: perfect_cube_binary_search() only accepts integers """ if not isinstance(n, int): raise TypeError("perfect_cube_binary_search() only accepts integers") + + # Handle zero and negative numbers + if n == 0: + return True if n < 0: n = -n - left = 0 - right = n + + # Quick checks to eliminate obvious non-cubes + # Check last three digits using modulo arithmetic + # Only 0, 1, 8, 7, 4, 5, 6, 3, 2, 9 can be cubes mod 10 + # But for cubes, the pattern is more complex + last_digit = n % 10 + if last_digit not in {0, 1, 8, 7, 4, 5, 6, 3, 2, 9}: + return False + + # More refined check: cubes mod 7 can only be 0, 1, 6 + if n % 7 not in {0, 1, 6}: + return False + + # More refined check: cubes mod 9 can only be 0, 1, 8 + if n % 9 not in {0, 1, 8}: + return False + + # Estimate the cube root using logarithms for very large numbers + # This gives us a much better initial right bound + if n > 10**18: + # For very large numbers, use logarithmic approximation + # to get a reasonable upper bound + log_n = len(str(n)) # Approximate log10(n) + approx_root = 10 ** (log_n // 3) + left = max(0, approx_root // 10) + right = approx_root * 10 + else: + # For smaller numbers, use the standard approach + left, right = 0, n // 2 + 1 + + # Binary search while left <= right: - mid = left + (right - left) // 2 - if mid * mid * mid == n: + mid = (left + right) // 2 + # Avoid computing mid*mid*mid for very large mid values + # by checking if mid is too large first + if mid > 10**6 and mid * mid > n // mid: + right = mid - 1 + continue + + cube = mid * mid * mid + if cube == n: return True - elif mid * mid * mid < n: + elif cube < n: left = mid + 1 else: right = mid - 1 + return False if __name__ == "__main__": import doctest - doctest.testmod() From 9f63385ba0f5a46a7fb30f18902e9f2d417ce944 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 19 Sep 2025 13:44:17 +0000 Subject: [PATCH 2/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- maths/perfect_cube.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/maths/perfect_cube.py b/maths/perfect_cube.py index 161231fb9224..b5e99a0ca62d 100644 --- a/maths/perfect_cube.py +++ b/maths/perfect_cube.py @@ -1,10 +1,10 @@ def perfect_cube(n: int) -> bool: """ Check if a number is a perfect cube or not. - + Note: This method uses floating point arithmetic which may be imprecise for very large numbers. - + >>> perfect_cube(27) True >>> perfect_cube(64) @@ -30,12 +30,12 @@ def perfect_cube(n: int) -> bool: is_negative = True else: is_negative = False - + val = n ** (1 / 3) # Round to avoid floating point precision issues rounded_val = round(val) result = rounded_val * rounded_val * rounded_val == n - + # For negative numbers, we need to check if the cube root would be negative return result and not (is_negative and rounded_val == 0) @@ -45,7 +45,7 @@ def perfect_cube_binary_search(n: int) -> bool: Check if a number is a perfect cube or not using binary search. Time complexity : O(Log(n)) Space complexity: O(1) - + >>> perfect_cube_binary_search(27) True >>> perfect_cube_binary_search(64) @@ -91,13 +91,13 @@ def perfect_cube_binary_search(n: int) -> bool: """ if not isinstance(n, int): raise TypeError("perfect_cube_binary_search() only accepts integers") - + # Handle zero and negative numbers if n == 0: return True if n < 0: n = -n - + # Quick checks to eliminate obvious non-cubes # Check last three digits using modulo arithmetic # Only 0, 1, 8, 7, 4, 5, 6, 3, 2, 9 can be cubes mod 10 @@ -105,15 +105,15 @@ def perfect_cube_binary_search(n: int) -> bool: last_digit = n % 10 if last_digit not in {0, 1, 8, 7, 4, 5, 6, 3, 2, 9}: return False - + # More refined check: cubes mod 7 can only be 0, 1, 6 if n % 7 not in {0, 1, 6}: return False - + # More refined check: cubes mod 9 can only be 0, 1, 8 if n % 9 not in {0, 1, 8}: return False - + # Estimate the cube root using logarithms for very large numbers # This gives us a much better initial right bound if n > 10**18: @@ -126,7 +126,7 @@ def perfect_cube_binary_search(n: int) -> bool: else: # For smaller numbers, use the standard approach left, right = 0, n // 2 + 1 - + # Binary search while left <= right: mid = (left + right) // 2 @@ -135,7 +135,7 @@ def perfect_cube_binary_search(n: int) -> bool: if mid > 10**6 and mid * mid > n // mid: right = mid - 1 continue - + cube = mid * mid * mid if cube == n: return True @@ -143,10 +143,11 @@ def perfect_cube_binary_search(n: int) -> bool: left = mid + 1 else: right = mid - 1 - + return False if __name__ == "__main__": import doctest + doctest.testmod() From 015c4879c5ecd755478a1df09e9549a7f8647404 Mon Sep 17 00:00:00 2001 From: lighting9999 Date: Fri, 19 Sep 2025 21:49:56 +0800 Subject: [PATCH 3/5] fix Doctests --- maths/perfect_cube.py | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/maths/perfect_cube.py b/maths/perfect_cube.py index b5e99a0ca62d..c016d5c7df18 100644 --- a/maths/perfect_cube.py +++ b/maths/perfect_cube.py @@ -1,10 +1,10 @@ def perfect_cube(n: int) -> bool: """ Check if a number is a perfect cube or not. - + Note: This method uses floating point arithmetic which may be imprecise for very large numbers. - + >>> perfect_cube(27) True >>> perfect_cube(64) @@ -30,12 +30,12 @@ def perfect_cube(n: int) -> bool: is_negative = True else: is_negative = False - + val = n ** (1 / 3) # Round to avoid floating point precision issues rounded_val = round(val) result = rounded_val * rounded_val * rounded_val == n - + # For negative numbers, we need to check if the cube root would be negative return result and not (is_negative and rounded_val == 0) @@ -45,7 +45,7 @@ def perfect_cube_binary_search(n: int) -> bool: Check if a number is a perfect cube or not using binary search. Time complexity : O(Log(n)) Space complexity: O(1) - + >>> perfect_cube_binary_search(27) True >>> perfect_cube_binary_search(64) @@ -70,7 +70,9 @@ def perfect_cube_binary_search(n: int) -> bool: False >>> perfect_cube_binary_search(10**100) # Extremely large number False - >>> perfect_cube_binary_search(10**300) # Extremely large number + >>> perfect_cube_binary_search(10**300) # Extremely large perfect cube (10^100)^3 + True + >>> perfect_cube_binary_search(10**300 + 1) # Extremely large non-perfect cube False >>> perfect_cube_binary_search("a") Traceback (most recent call last): @@ -91,13 +93,13 @@ def perfect_cube_binary_search(n: int) -> bool: """ if not isinstance(n, int): raise TypeError("perfect_cube_binary_search() only accepts integers") - + # Handle zero and negative numbers if n == 0: return True if n < 0: n = -n - + # Quick checks to eliminate obvious non-cubes # Check last three digits using modulo arithmetic # Only 0, 1, 8, 7, 4, 5, 6, 3, 2, 9 can be cubes mod 10 @@ -105,15 +107,15 @@ def perfect_cube_binary_search(n: int) -> bool: last_digit = n % 10 if last_digit not in {0, 1, 8, 7, 4, 5, 6, 3, 2, 9}: return False - + # More refined check: cubes mod 7 can only be 0, 1, 6 if n % 7 not in {0, 1, 6}: return False - + # More refined check: cubes mod 9 can only be 0, 1, 8 if n % 9 not in {0, 1, 8}: return False - + # Estimate the cube root using logarithms for very large numbers # This gives us a much better initial right bound if n > 10**18: @@ -126,7 +128,7 @@ def perfect_cube_binary_search(n: int) -> bool: else: # For smaller numbers, use the standard approach left, right = 0, n // 2 + 1 - + # Binary search while left <= right: mid = (left + right) // 2 @@ -135,7 +137,7 @@ def perfect_cube_binary_search(n: int) -> bool: if mid > 10**6 and mid * mid > n // mid: right = mid - 1 continue - + cube = mid * mid * mid if cube == n: return True @@ -143,11 +145,11 @@ def perfect_cube_binary_search(n: int) -> bool: left = mid + 1 else: right = mid - 1 - + return False if __name__ == "__main__": import doctest - doctest.testmod() + doctest.testmod() \ No newline at end of file From 203d358dd9c8d2854b807b42b5da23f1975f1400 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 19 Sep 2025 13:51:22 +0000 Subject: [PATCH 4/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- maths/perfect_cube.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/maths/perfect_cube.py b/maths/perfect_cube.py index c016d5c7df18..c792b766109b 100644 --- a/maths/perfect_cube.py +++ b/maths/perfect_cube.py @@ -1,10 +1,10 @@ def perfect_cube(n: int) -> bool: """ Check if a number is a perfect cube or not. - + Note: This method uses floating point arithmetic which may be imprecise for very large numbers. - + >>> perfect_cube(27) True >>> perfect_cube(64) @@ -30,12 +30,12 @@ def perfect_cube(n: int) -> bool: is_negative = True else: is_negative = False - + val = n ** (1 / 3) # Round to avoid floating point precision issues rounded_val = round(val) result = rounded_val * rounded_val * rounded_val == n - + # For negative numbers, we need to check if the cube root would be negative return result and not (is_negative and rounded_val == 0) @@ -45,7 +45,7 @@ def perfect_cube_binary_search(n: int) -> bool: Check if a number is a perfect cube or not using binary search. Time complexity : O(Log(n)) Space complexity: O(1) - + >>> perfect_cube_binary_search(27) True >>> perfect_cube_binary_search(64) @@ -93,13 +93,13 @@ def perfect_cube_binary_search(n: int) -> bool: """ if not isinstance(n, int): raise TypeError("perfect_cube_binary_search() only accepts integers") - + # Handle zero and negative numbers if n == 0: return True if n < 0: n = -n - + # Quick checks to eliminate obvious non-cubes # Check last three digits using modulo arithmetic # Only 0, 1, 8, 7, 4, 5, 6, 3, 2, 9 can be cubes mod 10 @@ -107,15 +107,15 @@ def perfect_cube_binary_search(n: int) -> bool: last_digit = n % 10 if last_digit not in {0, 1, 8, 7, 4, 5, 6, 3, 2, 9}: return False - + # More refined check: cubes mod 7 can only be 0, 1, 6 if n % 7 not in {0, 1, 6}: return False - + # More refined check: cubes mod 9 can only be 0, 1, 8 if n % 9 not in {0, 1, 8}: return False - + # Estimate the cube root using logarithms for very large numbers # This gives us a much better initial right bound if n > 10**18: @@ -128,7 +128,7 @@ def perfect_cube_binary_search(n: int) -> bool: else: # For smaller numbers, use the standard approach left, right = 0, n // 2 + 1 - + # Binary search while left <= right: mid = (left + right) // 2 @@ -137,7 +137,7 @@ def perfect_cube_binary_search(n: int) -> bool: if mid > 10**6 and mid * mid > n // mid: right = mid - 1 continue - + cube = mid * mid * mid if cube == n: return True @@ -145,11 +145,11 @@ def perfect_cube_binary_search(n: int) -> bool: left = mid + 1 else: right = mid - 1 - + return False if __name__ == "__main__": import doctest - doctest.testmod() \ No newline at end of file + doctest.testmod() From d35b3a6af04e381488ad34c38b2e4acdebc26433 Mon Sep 17 00:00:00 2001 From: lighting9999 Date: Sat, 20 Sep 2025 08:21:56 +0800 Subject: [PATCH 5/5] fix perfect_cube.py --- maths/perfect_cube.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/maths/perfect_cube.py b/maths/perfect_cube.py index c792b766109b..2e847bb6926b 100644 --- a/maths/perfect_cube.py +++ b/maths/perfect_cube.py @@ -25,12 +25,8 @@ def perfect_cube(n: int) -> bool: False """ # Handle negative numbers - if n < 0: + if is_negative := n < 0: n = -n - is_negative = True - else: - is_negative = False - val = n ** (1 / 3) # Round to avoid floating point precision issues rounded_val = round(val)