How to enumerate x^2 + y^2 = z^2 - 1 (with additional constraints)

前端 未结 6 2077
野性不改
野性不改 2021-02-04 09:33

Lets N be a number (10<=N<=10^5).

I have to break it into 3 numbers (x,y,z) such that it validates the following conditions.

6条回答
  •  一向
    一向 (楼主)
    2021-02-04 10:16

    Here is a simple improvement in Python (converting to the faster equivalent in C-based code is left as an exercise for the reader). To get accurate timing for the computation, I removed printing the solutions themselves (after validating them in a previous run).

    • Use an outer loop for one free variable (I chose z), constrained only by its relation to N.
    • Use an inner loop (I chose y) constrained by the outer loop index.
    • The third variable is directly computed per requirement 2.

    Timing results:

    -------------------- 10 
     1 solutions found in 2.3365020751953125e-05  sec.
    -------------------- 100 
     6 solutions found in 0.00040078163146972656  sec.
    -------------------- 1000 
     55 solutions found in 0.030081748962402344  sec.
    -------------------- 10000 
     543 solutions found in 2.2078349590301514  sec.
    -------------------- 100000 
     5512 solutions found in 214.93411707878113  sec.
    

    That's 3:35 for the large case, plus your time to collate and/or print the results.

    If you need faster code (this is still pretty brute-force), look into Diophantine equations and parameterizations to generate (y, x) pairs, given the target value of z^2 - 1.

    import math
    import time
    
    def break3(N):
        """
        10 <= N <= 10^5
        return x, y, z triples such that:
            x <= y <= z
            x^2 + y^2 = z^2 - 1        
            x + y + z <= N
        """
    
        """
        Observations:
        z <= x + y
        z < N/2
        """
    
        count = 0
        z_limit = N // 2
        for z in range(3, z_limit):
    
            # Since y >= x, there's a lower bound on y
            target = z*z - 1
            ymin = int(math.sqrt(target/2))
            for y in range(ymin, z):
                # Given y and z, compute x.
                # That's a solution iff x is integer.
                x_target = target - y*y
                x = int(math.sqrt(x_target))
                if x*x == x_target and x+y+z <= N:
                    # print("solution", x, y, z)
                    count += 1
    
        return count
    
    
    test = [10, 100, 1000, 10**4, 10**5]
    border = "-"*20
    
    for case in test: 
        print(border, case)
        start = time.time()
        print(break3(case), "solutions found in", time.time() - start, "sec.")
    

提交回复
热议问题