Skip to content

⚡️ Speed up function lcm by 27% #47

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

codeflash-ai[bot]
Copy link

@codeflash-ai codeflash-ai bot commented Jul 24, 2025

📄 27% (0.27x) speedup for lcm in src/math/computation.py

⏱️ Runtime : 3.83 milliseconds 3.01 milliseconds (best of 109 runs)

📝 Explanation and details

Here is your optimized code. The main improvement is moving the gcd function outside so it isn't redefined on every call to lcm. This reduces function creation overhead, especially if lcm is called multiple times.

This avoids the inner function allocation, improving both speed and memory, especially for repeated calls.

Correctness verification report:

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

# unit tests

# -------------------------------
# 1. Basic Test Cases
# -------------------------------

def test_lcm_basic_coprime():
    # Coprime numbers: lcm(3, 5) = 15
    codeflash_output = lcm(3, 5) # 875ns -> 709ns (23.4% faster)

def test_lcm_basic_one_is_multiple_of_other():
    # One is a multiple of the other: lcm(4, 8) = 8
    codeflash_output = lcm(4, 8) # 833ns -> 666ns (25.1% faster)

def test_lcm_basic_both_same():
    # Both numbers are the same: lcm(7, 7) = 7
    codeflash_output = lcm(7, 7) # 708ns -> 542ns (30.6% faster)

def test_lcm_basic_small_numbers():
    # Small numbers: lcm(2, 6) = 6
    codeflash_output = lcm(2, 6) # 750ns -> 666ns (12.6% faster)
    # lcm(9, 6) = 18
    codeflash_output = lcm(9, 6) # 417ns -> 334ns (24.9% faster)

def test_lcm_basic_one_is_one():
    # One number is 1: lcm(1, 13) = 13
    codeflash_output = lcm(1, 13) # 750ns -> 583ns (28.6% faster)
    # lcm(1, 1) = 1
    codeflash_output = lcm(1, 1) # 375ns -> 292ns (28.4% faster)

# -------------------------------
# 2. Edge Test Cases
# -------------------------------

def test_lcm_zero_cases():
    # If either input is zero, lcm should be zero
    codeflash_output = lcm(0, 5) # 333ns -> 208ns (60.1% faster)
    codeflash_output = lcm(7, 0) # 209ns -> 167ns (25.1% faster)
    codeflash_output = lcm(0, 0) # 208ns -> 125ns (66.4% faster)

def test_lcm_negative_numbers():
    # Negative numbers should be handled as absolute values
    codeflash_output = lcm(-3, 5) # 916ns -> 708ns (29.4% faster)
    codeflash_output = lcm(3, -5) # 500ns -> 417ns (19.9% faster)
    codeflash_output = lcm(-3, -5) # 417ns -> 417ns (0.000% faster)

def test_lcm_negative_and_zero():
    # Negative and zero: lcm(-7, 0) = 0
    codeflash_output = lcm(-7, 0) # 375ns -> 250ns (50.0% faster)
    codeflash_output = lcm(0, -8) # 250ns -> 167ns (49.7% faster)

def test_lcm_large_and_small():
    # Large and small number: lcm(1, 999983) = 999983
    codeflash_output = lcm(1, 999983) # 875ns -> 791ns (10.6% faster)

def test_lcm_prime_numbers():
    # Two large primes: lcm(101, 103) = 10403
    codeflash_output = lcm(101, 103) # 875ns -> 791ns (10.6% faster)

def test_lcm_one_is_negative_multiple_of_other():
    # lcm(-12, 4) = 12
    codeflash_output = lcm(-12, 4) # 833ns -> 667ns (24.9% faster)
    # lcm(12, -4) = 12
    codeflash_output = lcm(12, -4) # 541ns -> 417ns (29.7% faster)

def test_lcm_large_gcd():
    # Large GCD: lcm(100, 80) = 400
    codeflash_output = lcm(100, 80) # 833ns -> 708ns (17.7% faster)

def test_lcm_min_int():
    # Edge of 32-bit integer range (simulate)
    min_int = -2**31
    codeflash_output = lcm(min_int, 2) # 1.08μs -> 959ns (12.9% faster)

def test_lcm_max_int():
    # Edge of 32-bit integer range (simulate)
    max_int = 2**31 - 1
    codeflash_output = lcm(max_int, 1) # 917ns -> 834ns (9.95% faster)

# -------------------------------
# 3. Large Scale Test Cases
# -------------------------------

def test_lcm_large_numbers():
    # Test with two large numbers
    a = 123456
    b = 789012
    # lcm(123456, 789012) = 8117355456
    codeflash_output = lcm(a, b) # 1.42μs -> 1.38μs (3.05% faster)

def test_lcm_large_prime_factors():
    # Large numbers with large prime factors
    a = 99991
    b = 99989
    codeflash_output = lcm(a, b) # 958ns -> 833ns (15.0% faster)

def test_lcm_large_power_of_two():
    # Large powers of two: lcm(2**20, 2**18) = 2**20
    codeflash_output = lcm(2**20, 2**18) # 750ns -> 709ns (5.78% faster)

def test_lcm_large_and_small_mixed_sign():
    # Large positive and large negative
    a = 10**9
    b = -10**8
    codeflash_output = lcm(a, b) # 875ns -> 750ns (16.7% faster)

def test_lcm_many_pairs_performance():
    # Test lcm on many pairs for performance and correctness
    for i in range(1, 1001):
        for j in range(1, 11):  # keep inner loop small for speed
            # lcm(i, j) should be divisible by both i and j
            codeflash_output = lcm(i, j); result = codeflash_output

def test_lcm_large_loop_edge_values():
    # Test lcm for values near 1000
    for i in range(990, 1001):
        for j in range(990, 1001):
            codeflash_output = lcm(i, j); result = codeflash_output

# -------------------------------
# 4. Additional Correctness & Symmetry
# -------------------------------

def test_lcm_symmetry():
    # lcm(a, b) == lcm(b, a)
    pairs = [(2, 3), (5, 10), (123, 456), (-7, 21), (0, 42)]
    for a, b in pairs:
        codeflash_output = lcm(a, b) # 2.83μs -> 2.38μs (19.2% faster)

def test_lcm_divides_product():
    # lcm(a, b) * gcd(a, b) == abs(a * b) for nonzero a, b
    def gcd(x, y):
        while y:
            x, y = y, x % y
        return x
    for a in range(-10, 11):
        for b in range(-10, 11):
            if a == 0 or b == 0:
                continue
            codeflash_output = lcm(a, b); l = codeflash_output
            g = gcd(a, b)
# 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 lcm

# unit tests

# 1. Basic Test Cases

def test_lcm_basic_positive_numbers():
    # LCM of two coprime numbers
    codeflash_output = lcm(3, 5) # 833ns -> 667ns (24.9% faster)
    # LCM where one is multiple of the other
    codeflash_output = lcm(4, 8) # 375ns -> 292ns (28.4% faster)
    # LCM of two equal numbers
    codeflash_output = lcm(7, 7) # 333ns -> 250ns (33.2% faster)
    # LCM of two composite numbers
    codeflash_output = lcm(6, 8) # 292ns -> 291ns (0.344% faster)
    # LCM with 1 (should be the other number)
    codeflash_output = lcm(1, 9) # 333ns -> 250ns (33.2% faster)
    codeflash_output = lcm(9, 1) # 292ns -> 208ns (40.4% faster)

def test_lcm_basic_negative_numbers():
    # LCM should be positive even if inputs are negative
    codeflash_output = lcm(-3, 5) # 833ns -> 709ns (17.5% faster)
    codeflash_output = lcm(3, -5) # 458ns -> 417ns (9.83% faster)
    codeflash_output = lcm(-3, -5) # 458ns -> 375ns (22.1% faster)
    # LCM with negative and positive, one is multiple of the other
    codeflash_output = lcm(-4, 8) # 375ns -> 250ns (50.0% faster)
    codeflash_output = lcm(4, -8) # 500ns -> 417ns (19.9% faster)

def test_lcm_basic_zero_cases():
    # LCM with zero should always be 0
    codeflash_output = lcm(0, 5) # 375ns -> 208ns (80.3% faster)
    codeflash_output = lcm(5, 0) # 250ns -> 125ns (100% faster)
    codeflash_output = lcm(0, 0) # 208ns -> 125ns (66.4% faster)

# 2. Edge Test Cases

def test_lcm_edge_one_and_negative_one():
    # LCM with 1 or -1 should be abs(other)
    codeflash_output = lcm(1, -1) # 708ns -> 583ns (21.4% faster)
    codeflash_output = lcm(-1, 1) # 375ns -> 292ns (28.4% faster)
    codeflash_output = lcm(-1, -1) # 333ns -> 291ns (14.4% faster)
    codeflash_output = lcm(1, 0) # 250ns -> 166ns (50.6% faster)
    codeflash_output = lcm(0, 1) # 208ns -> 125ns (66.4% faster)

def test_lcm_edge_large_and_small():
    # LCM of a large number and a small number
    codeflash_output = lcm(1_000_000_007, 2) # 1.00μs -> 916ns (9.17% faster)
    # LCM of a large number and 1
    codeflash_output = lcm(1_000_000_007, 1) # 458ns -> 375ns (22.1% faster)
    # LCM of a large negative and small positive
    codeflash_output = lcm(-1_000_000_007, 2) # 500ns -> 417ns (19.9% faster)

def test_lcm_edge_primes_and_composites():
    # LCM of two large primes
    codeflash_output = lcm(101, 103) # 917ns -> 750ns (22.3% faster)
    # LCM of a prime and a composite sharing a factor
    codeflash_output = lcm(13, 26) # 458ns -> 375ns (22.1% faster)
    # LCM of two numbers where GCD is not 1
    codeflash_output = lcm(12, 18) # 416ns -> 333ns (24.9% faster)

def test_lcm_edge_large_negative_numbers():
    # LCM of two large negative numbers
    codeflash_output = lcm(-100000, -250000) # 1.08μs -> 917ns (18.1% faster)

def test_lcm_edge_minimal_inputs():
    # LCM of minimal positive and negative integers
    codeflash_output = lcm(1, 1) # 708ns -> 583ns (21.4% faster)
    codeflash_output = lcm(-1, -1) # 375ns -> 292ns (28.4% faster)
    codeflash_output = lcm(1, -1) # 333ns -> 250ns (33.2% faster)
    codeflash_output = lcm(-1, 1) # 292ns -> 250ns (16.8% faster)

def test_lcm_edge_symmetry():
    # LCM should be symmetric: lcm(a, b) == lcm(b, a)
    for a, b in [(3, 5), (0, 7), (-4, 6), (100, 250), (1, 999)]:
        codeflash_output = lcm(a, b) # 2.46μs -> 2.04μs (20.3% faster)

def test_lcm_edge_large_gcd():
    # LCM where GCD is large
    codeflash_output = lcm(100000, 50000) # 875ns -> 750ns (16.7% faster)

# 3. Large Scale Test Cases

def test_lcm_large_numbers():
    # LCM of two large numbers (but not exceeding Python's int)
    a = 123456789
    b = 987654321
    # Precomputed LCM: 13548070123626141
    codeflash_output = lcm(a, b) # 1.08μs -> 917ns (18.1% faster)

def test_lcm_large_prime_and_composite():
    # LCM of a large prime and a large composite
    a = 999983  # large prime
    b = 999980  # composite
    # GCD is 1, so LCM is product
    codeflash_output = lcm(a, b) # 1.04μs -> 875ns (19.1% faster)

def test_lcm_large_scale_array_pairs():
    # Test LCM for many pairs to check performance/scalability
    # (not exceeding 1000 iterations)
    for i in range(1, 1001):
        codeflash_output = lcm(i, i+1) # 332μs -> 263μs (26.2% faster)

def test_lcm_large_scale_multiples_of_10():
    # LCM of numbers that are all multiples of 10
    for i in range(10, 1001, 10):
        codeflash_output = lcm(i, 1000) # 41.7μs -> 35.2μs (18.3% faster)

def test_lcm_large_scale_randomized_pairs():
    # Test a selection of large and random pairs
    test_cases = [
        (999999937, 999999929),  # both large primes
        (123456789, 987654321),
        (100000000, 100000001),
        (999999999, 2),
        (500000000, 400000000),
        (999999991, 999999989),
    ]
    expected = [
        999999866000006353,  # product of the two primes
        13548070123626141,
        10000000100000000,
        1999999998,
        2000000000,
        999999980000000099,
    ]
    for (a, b), exp in zip(test_cases, expected):
        codeflash_output = lcm(a, b) # 3.33μs -> 2.83μs (17.6% faster)

def test_lcm_large_scale_negative_pairs():
    # LCM with large negative numbers
    for i in range(-1000, 0):
        pass

# Helper function for above test
def gcd(x, y):
    while y:
        x, y = y, x % y
    return abs(x)
# 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 lcm

def test_lcm():
    lcm(-39, -4)

def test_lcm_2():
    lcm(-1, 0)

To edit these changes git checkout codeflash/optimize-lcm-mdgvyr4g and push.

Codeflash

Here is your optimized code. The main improvement is moving the gcd function outside so it isn't redefined on every call to lcm. This reduces function creation overhead, especially if lcm is called multiple times.


This avoids the inner function allocation, improving both speed and memory, especially for repeated calls.
@codeflash-ai codeflash-ai bot added the ⚡️ codeflash Optimization PR opened by Codeflash AI label Jul 24, 2025
@codeflash-ai codeflash-ai bot requested a review from KRRT7 July 24, 2025 04:22
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
Projects
None yet
Development

Successfully merging this pull request may close these issues.

0 participants