Skip to content

Conversation

@codeflash-ai
Copy link

@codeflash-ai codeflash-ai bot commented Oct 29, 2025

📄 12% (0.12x) speedup for gcd_recursive in src/math/computation.py

⏱️ Runtime : 34.1 microseconds 30.3 microseconds (best of 492 runs)

📝 Explanation and details

The optimization converts the recursive Euclidean algorithm to an iterative implementation, eliminating function call overhead. Instead of making recursive calls with return gcd_recursive(b, a % b), the optimized version uses a while loop that updates variables in-place with a, b = b, a % b.

Key Performance Improvements:

  • Eliminated recursive function calls: Each recursive call in Python involves stack frame creation/destruction overhead. The line profiler shows the recursive call line consumed 71.1% of total time (811000ns) in the original version.
  • Reduced memory overhead: No stack frames are allocated for each iteration, improving memory efficiency.
  • Maintained algorithmic efficiency: Both versions perform the same number of modulo operations, but the iterative approach avoids the call stack overhead.

The line profiler results demonstrate this improvement: total execution time dropped from 1.141ms to 0.258ms (77% reduction), with the iterative loop operations being significantly faster per hit (329.3ns vs 3257ns per operation).

Test Case Performance:
The optimization shows consistent improvements across most test cases, with particularly strong gains (25-40% faster) on cases requiring multiple iterations like large numbers, Fibonacci sequences, and deep GCD computations. Simple cases (like GCD with 0) show smaller or no improvements since they terminate immediately, bypassing the recursive overhead advantage.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 84 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Generated Regression Tests and Runtime
import pytest  # used for our unit tests
from src.math.computation import gcd_recursive

# unit tests

# ----------- Basic Test Cases -----------

def test_gcd_basic_coprime():
    # Coprime numbers: GCD should be 1
    codeflash_output = gcd_recursive(13, 17) # 459ns -> 500ns (8.20% slower)
    codeflash_output = gcd_recursive(29, 12) # 333ns -> 250ns (33.2% faster)
    codeflash_output = gcd_recursive(101, 10) # 208ns -> 167ns (24.6% faster)

def test_gcd_basic_non_coprime():
    # Non-coprime numbers: GCD should be their common factor
    codeflash_output = gcd_recursive(20, 30) # 500ns -> 458ns (9.17% faster)
    codeflash_output = gcd_recursive(100, 80) # 208ns -> 167ns (24.6% faster)
    codeflash_output = gcd_recursive(81, 27) # 166ns -> 125ns (32.8% faster)

def test_gcd_basic_swap_order():
    # GCD should be commutative: gcd(a, b) == gcd(b, a)
    codeflash_output = gcd_recursive(30, 20) # 458ns -> 417ns (9.83% faster)
    codeflash_output = gcd_recursive(81, 27) # 166ns -> 167ns (0.599% slower)
    codeflash_output = gcd_recursive(17, 13) # 250ns -> 208ns (20.2% faster)

def test_gcd_basic_equal_numbers():
    # GCD of a number with itself is the number
    codeflash_output = gcd_recursive(15, 15) # 333ns -> 333ns (0.000% faster)
    codeflash_output = gcd_recursive(100, 100) # 167ns -> 125ns (33.6% faster)

# ----------- Edge Test Cases -----------

def test_gcd_edge_zero_and_number():
    # GCD of 0 and any number is the absolute value of that number
    codeflash_output = gcd_recursive(0, 5) # 375ns -> 416ns (9.86% slower)
    codeflash_output = gcd_recursive(5, 0) # 125ns -> 125ns (0.000% faster)
    codeflash_output = gcd_recursive(0, 0) # 83ns -> 83ns (0.000% faster)

def test_gcd_edge_negative_numbers():
    # GCD should handle negative numbers and always return non-negative result
    codeflash_output = gcd_recursive(-20, 30) # 417ns -> 417ns (0.000% faster)
    codeflash_output = gcd_recursive(20, -30) # 333ns -> 292ns (14.0% faster)
    codeflash_output = gcd_recursive(-20, -30) # 333ns -> 292ns (14.0% faster)
    codeflash_output = gcd_recursive(-17, -13) # 250ns -> 208ns (20.2% faster)
    codeflash_output = gcd_recursive(0, -5) # 167ns -> 125ns (33.6% faster)
    codeflash_output = gcd_recursive(-5, 0) # 83ns -> 83ns (0.000% faster)

def test_gcd_edge_one_and_zero():
    # GCD with 1 and 0
    codeflash_output = gcd_recursive(1, 0) # 208ns -> 209ns (0.478% slower)
    codeflash_output = gcd_recursive(0, 1) # 292ns -> 292ns (0.000% faster)

def test_gcd_edge_one_and_any_number():
    # GCD of 1 and any number is 1
    codeflash_output = gcd_recursive(1, 999) # 458ns -> 417ns (9.83% faster)
    codeflash_output = gcd_recursive(999, 1) # 167ns -> 166ns (0.602% faster)
    codeflash_output = gcd_recursive(-1, 999) # 333ns -> 292ns (14.0% faster)
    codeflash_output = gcd_recursive(999, -1) # 125ns -> 125ns (0.000% faster)

def test_gcd_edge_large_negative_and_positive():
    # Negative and positive large numbers
    codeflash_output = gcd_recursive(-100000, 250000) # 625ns -> 541ns (15.5% faster)
    codeflash_output = gcd_recursive(100000, -250000) # 333ns -> 291ns (14.4% faster)

def test_gcd_edge_prime_and_multiple():
    # Prime number and its multiple
    codeflash_output = gcd_recursive(7, 21) # 417ns -> 417ns (0.000% faster)
    codeflash_output = gcd_recursive(21, 7) # 167ns -> 125ns (33.6% faster)

def test_gcd_edge_zero_and_zero():
    # Both numbers zero: by definition, GCD(0, 0) is 0
    codeflash_output = gcd_recursive(0, 0) # 209ns -> 208ns (0.481% faster)

# ----------- Large Scale Test Cases -----------

def test_gcd_large_numbers():
    # Large numbers, should not exceed recursion limit
    codeflash_output = gcd_recursive(123456789, 987654321) # 542ns -> 500ns (8.40% faster)
    codeflash_output = gcd_recursive(10**12, 10**9) # 209ns -> 208ns (0.481% faster)
    codeflash_output = gcd_recursive(999999937, 999999929) # 250ns -> 250ns (0.000% faster)

def test_gcd_large_numbers_with_common_factor():
    # Large numbers with a common factor
    codeflash_output = gcd_recursive(10**6 * 123, 10**6 * 456) # 750ns -> 625ns (20.0% faster)
    codeflash_output = gcd_recursive(9876543210, 1234567890) # 458ns -> 375ns (22.1% faster)

def test_gcd_large_numbers_with_zero():
    # Large number and zero
    codeflash_output = gcd_recursive(10**18, 0) # 250ns -> 208ns (20.2% faster)
    codeflash_output = gcd_recursive(0, 10**18) # 334ns -> 334ns (0.000% faster)

def test_gcd_large_negative_numbers():
    # Large negative numbers
    codeflash_output = gcd_recursive(-10**12, -10**9) # 417ns -> 375ns (11.2% faster)
    codeflash_output = gcd_recursive(-999999937, -999999929) # 375ns -> 292ns (28.4% faster)

def test_gcd_large_numbers_commutativity():
    # Large numbers, commutativity check
    a = 10**8 * 7
    b = 10**8 * 13
    codeflash_output = gcd_recursive(a, b) # 667ns -> 583ns (14.4% faster)
    codeflash_output = gcd_recursive(b, a) # 292ns -> 250ns (16.8% faster)

# ----------- Miscellaneous Robustness -----------

def test_gcd_recursive_is_pure():
    # The function should not modify its arguments
    a, b = 48, 18
    orig_a, orig_b = a, b
    codeflash_output = gcd_recursive(a, b); result = codeflash_output # 500ns -> 417ns (19.9% faster)


def test_gcd_recursive_large_recursion_depth():
    # Should handle deep recursion for large coprime numbers
    # For two consecutive Fibonacci numbers, GCD is 1
    # Fibonacci(30) = 832040, Fibonacci(31) = 1346269
    codeflash_output = gcd_recursive(832040, 1346269) # 1.88μs -> 1.46μs (28.5% faster)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
#------------------------------------------------
import pytest  # used for our unit tests
from src.math.computation import gcd_recursive

# unit tests

# -----------------------
# Basic Test Cases
# -----------------------

def test_gcd_basic_coprime():
    # Coprime numbers (no common divisor other than 1)
    codeflash_output = gcd_recursive(13, 17) # 542ns -> 500ns (8.40% faster)
    codeflash_output = gcd_recursive(17, 13) # 292ns -> 208ns (40.4% faster)

def test_gcd_basic_common_divisor():
    # Numbers with a common divisor
    codeflash_output = gcd_recursive(12, 8) # 458ns -> 417ns (9.83% faster)
    codeflash_output = gcd_recursive(8, 12) # 250ns -> 208ns (20.2% faster)

def test_gcd_basic_equal_numbers():
    # GCD of a number with itself is the number
    codeflash_output = gcd_recursive(7, 7) # 375ns -> 334ns (12.3% faster)
    codeflash_output = gcd_recursive(0, 0) # 125ns -> 125ns (0.000% faster)

def test_gcd_basic_one_zero():
    # GCD with zero
    codeflash_output = gcd_recursive(0, 5) # 375ns -> 375ns (0.000% faster)
    codeflash_output = gcd_recursive(5, 0) # 125ns -> 83ns (50.6% faster)

def test_gcd_basic_one_as_argument():
    # GCD with 1
    codeflash_output = gcd_recursive(1, 999) # 417ns -> 417ns (0.000% faster)
    codeflash_output = gcd_recursive(999, 1) # 167ns -> 167ns (0.000% faster)

# -----------------------
# Edge Test Cases
# -----------------------

def test_gcd_negative_numbers():
    # Negative numbers should return positive GCD
    codeflash_output = gcd_recursive(-12, 8) # 458ns -> 417ns (9.83% faster)
    codeflash_output = gcd_recursive(12, -8) # 208ns -> 208ns (0.000% faster)
    codeflash_output = gcd_recursive(-12, -8) # 208ns -> 167ns (24.6% faster)

def test_gcd_zero_and_negative():
    # Zero and negative number
    codeflash_output = gcd_recursive(0, -7) # 375ns -> 375ns (0.000% faster)
    codeflash_output = gcd_recursive(-7, 0) # 166ns -> 167ns (0.599% slower)

def test_gcd_large_and_small():
    # Large and small number
    codeflash_output = gcd_recursive(1000000, 2) # 417ns -> 375ns (11.2% faster)
    codeflash_output = gcd_recursive(2, 1000000) # 250ns -> 250ns (0.000% faster)

def test_gcd_prime_and_composite():
    # Prime and composite number
    codeflash_output = gcd_recursive(13, 26) # 458ns -> 417ns (9.83% faster)
    codeflash_output = gcd_recursive(26, 13) # 208ns -> 167ns (24.6% faster)

def test_gcd_one_negative_one():
    # Edge case: 1 and -1
    codeflash_output = gcd_recursive(1, -1) # 375ns -> 375ns (0.000% faster)
    codeflash_output = gcd_recursive(-1, 1) # 167ns -> 125ns (33.6% faster)
    codeflash_output = gcd_recursive(-1, -1) # 125ns -> 125ns (0.000% faster)

def test_gcd_zero_and_zero():
    # Edge case: both arguments zero
    codeflash_output = gcd_recursive(0, 0) # 209ns -> 250ns (16.4% slower)

def test_gcd_large_negative_numbers():
    # Large negative numbers
    codeflash_output = gcd_recursive(-1000000, -500000) # 375ns -> 375ns (0.000% faster)

# -----------------------
# Large Scale Test Cases
# -----------------------

def test_gcd_large_numbers():
    # Large numbers with known GCD
    a = 123456789012345678
    b = 987654321098765432
    codeflash_output = gcd_recursive(a, b) # 1.62μs -> 1.29μs (25.9% faster)

def test_gcd_large_coprime():
    # Large coprime numbers
    a = 1000003  # prime
    b = 999983   # prime
    codeflash_output = gcd_recursive(a, b) # 625ns -> 583ns (7.20% faster)

def test_gcd_large_power_of_two():
    # Large powers of two
    a = 2**500
    b = 2**300
    codeflash_output = gcd_recursive(a, b) # 875ns -> 792ns (10.5% faster)

def test_gcd_large_multiple():
    # Large numbers, one is a multiple of the other
    a = 999999999999999999
    b = 333333333333333333
    codeflash_output = gcd_recursive(a, b) # 583ns -> 500ns (16.6% faster)

def test_gcd_large_nontrivial():
    # Large numbers with nontrivial GCD
    a = 987654321234567890
    b = 123456789012345678
    # Compute expected GCD using the same function for determinism
    codeflash_output = gcd_recursive(a, b); expected = codeflash_output # 1.83μs -> 1.46μs (25.7% faster)
    codeflash_output = gcd_recursive(a, b) # 1.33μs -> 1.04μs (27.9% faster)

# -----------------------
# Additional Edge Cases
# -----------------------

@pytest.mark.parametrize("a,b,expected", [
    (0, 0, 0),            # both zero
    (0, 1, 1),            # zero and one
    (1, 0, 1),            # one and zero
    (0, -1, 1),           # zero and negative one
    (-1, 0, 1),           # negative one and zero
    (2, 2, 2),            # both equal positive
    (-2, -2, 2),          # both equal negative
    (2, -2, 2),           # positive and negative equal
    (-2, 2, 2),           # negative and positive equal
])
def test_gcd_parametrized_edge_cases(a, b, expected):
    # Parametrized edge cases for coverage
    codeflash_output = gcd_recursive(a, b) # 2.75μs -> 2.79μs (1.47% slower)

# -----------------------
# Performance/Recursion Depth
# -----------------------

def test_gcd_recursion_depth():
    # Test recursion depth with numbers that require many steps
    # For two consecutive Fibonacci numbers, GCD is 1, and recursion depth is maximal
    fib = [1, 1]
    for _ in range(2, 30):
        fib.append(fib[-1] + fib[-2])
    a, b = fib[-1], fib[-2]
    codeflash_output = gcd_recursive(a, b) # 1.67μs -> 1.33μs (25.0% faster)
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
#------------------------------------------------
from src.math.computation import gcd_recursive

def test_gcd_recursive():
    gcd_recursive(21, -76)

To edit these changes git checkout codeflash/optimize-gcd_recursive-mhbepnqx and push.

Codeflash

The optimization converts the recursive Euclidean algorithm to an iterative implementation, eliminating function call overhead. Instead of making recursive calls with `return gcd_recursive(b, a % b)`, the optimized version uses a `while` loop that updates variables in-place with `a, b = b, a % b`.

**Key Performance Improvements:**
- **Eliminated recursive function calls**: Each recursive call in Python involves stack frame creation/destruction overhead. The line profiler shows the recursive call line consumed 71.1% of total time (811000ns) in the original version.
- **Reduced memory overhead**: No stack frames are allocated for each iteration, improving memory efficiency.
- **Maintained algorithmic efficiency**: Both versions perform the same number of modulo operations, but the iterative approach avoids the call stack overhead.

The line profiler results demonstrate this improvement: total execution time dropped from 1.141ms to 0.258ms (77% reduction), with the iterative loop operations being significantly faster per hit (329.3ns vs 3257ns per operation).

**Test Case Performance:**
The optimization shows consistent improvements across most test cases, with particularly strong gains (25-40% faster) on cases requiring multiple iterations like large numbers, Fibonacci sequences, and deep GCD computations. Simple cases (like GCD with 0) show smaller or no improvements since they terminate immediately, bypassing the recursive overhead advantage.
@codeflash-ai codeflash-ai bot requested a review from KRRT7 October 29, 2025 02:59
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash labels Oct 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: High Optimization Quality according to Codeflash

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant