Generating unique, ordered Pythagorean triplets

前端 未结 19 1299
借酒劲吻你
借酒劲吻你 2020-11-29 16:57

This is a program I wrote to calculate Pythagorean triplets. When I run the program it prints each set of triplets twice because of the if statement. Is there any way I can

19条回答
  •  鱼传尺愫
    2020-11-29 17:51

    def pyth_triplets(n=1000):
        "Version 1"
        for x in xrange(1, n):
            x2= x*x # time saver
            for y in xrange(x+1, n): # y > x
                z2= x2 + y*y
                zs= int(z2**.5)
                if zs*zs == z2:
                    yield x, y, zs
    
    >>> print list(pyth_triplets(20))
    [(3, 4, 5), (5, 12, 13), (6, 8, 10), (8, 15, 17), (9, 12, 15), (12, 16, 20)]
    

    V.1 algorithm has monotonically increasing x values.

    EDIT

    It seems this question is still alive :)
    Since I came back and revisited the code, I tried a second approach which is almost 4 times as fast (about 26% of CPU time for N=10000) as my previous suggestion since it avoids lots of unnecessary calculations:

    def pyth_triplets(n=1000):
        "Version 2"
        for z in xrange(5, n+1):
            z2= z*z # time saver
            x= x2= 1
            y= z - 1; y2= y*y
            while x < y:
                x2_y2= x2 + y2
                if x2_y2 == z2:
                    yield x, y, z
                    x+= 1; x2= x*x
                    y-= 1; y2= y*y
                elif x2_y2 < z2:
                    x+= 1; x2= x*x
                else:
                    y-= 1; y2= y*y
    
    >>> print list(pyth_triplets(20))
    [(3, 4, 5), (6, 8, 10), (5, 12, 13), (9, 12, 15), (8, 15, 17), (12, 16, 20)]
    

    Note that this algorithm has increasing z values.

    If the algorithm was converted to C —where, being closer to the metal, multiplications take more time than additions— one could minimalise the necessary multiplications, given the fact that the step between consecutive squares is:

    (x+1)² - x² = (x+1)(x+1) - x² = x² + 2x + 1 - x² = 2x + 1

    so all of the inner x2= x*x and y2= y*y would be converted to additions and subtractions like this:

    def pyth_triplets(n=1000):
        "Version 3"
        for z in xrange(5, n+1):
            z2= z*z # time saver
            x= x2= 1; xstep= 3
            y= z - 1; y2= y*y; ystep= 2*y - 1
            while x < y:
                x2_y2= x2 + y2
                if x2_y2 == z2:
                    yield x, y, z
                    x+= 1; x2+= xstep; xstep+= 2
                    y-= 1; y2-= ystep; ystep-= 2
                elif x2_y2 < z2:
                    x+= 1; x2+= xstep; xstep+= 2
                else:
                    y-= 1; y2-= ystep; ystep-= 2
    

    Of course, in Python the extra bytecode produced actually slows down the algorithm compared to version 2, but I would bet (without checking :) that V.3 is faster in C.

    Cheers everyone :)

提交回复
热议问题