生成独特的有序毕达哥拉斯三胞胎

时间:2009-02-22 16:00:34

标签: python math

这是我写的计算毕达哥拉斯三胞胎的程序。当我运行程序时,由于if语句,它会打印两组三元组。有什么办法我可以告诉程序只打印一组新的三元组吗?感谢。

import math

def main():
    for x in range (1, 1000):
        for y in range (1, 1000):
            for z in range(1, 1000):
                if x*x == y*y + z*z:
                    print y, z, x
                    print '-'*50

if __name__ == '__main__':
    main()  

20 个答案:

答案 0 :(得分:72)

Pythagorean Triples为声称“ for循环被视为有害”提供了一个很好的例子,因为for循环引诱我们思考计数,通常是最无关紧要的部分任务。

(我将坚持使用伪代码来避免语言偏差,并且为了简化伪代码,我不会优化掉例如x * xy * y的多个计算。 )

版本1

for x in 1..N {
    for y in 1..N {
        for z in 1..N {
            if x * x + y * y == z * z then {
                // use x, y, z
            }
        }
    }
}

是最糟糕的解决方案。它生成重复项,并遍历空间中无用的部分(例如,每当z < y时)。它的时间复杂度在N上是立方的。

版本2 ,第一项改进来自要求x < y < z保留,如:

for x in 1..N {
    for y in x+1..N {
        for z in y+1..N {
            if x * x + y * y == z * z then {
                // use x, y, z
            }
        }
    }
}

可减少运行时间并消除重复的解决方案。但是,它仍然是N的立方;改善只是降低了N - 立方体的系数。

z不再成立后继续检查z * z < x * x + y * y的增加值是毫无意义的。这个事实激发了第3版,这是远离z的蛮力迭代的第一步:

for x in 1..N {
    for y in x+1..N {
        z = y + 1
        while z * z < x * x + y * y {
            z = z + 1
        }
        if z * z == x * x + y * y and z <= N then {
            // use x, y, z
        }
    }
}

对于1000的N,这比版本2快5倍,但在N立方。

下一个见解是xy是唯一的自变量; z取决于其值,并且为z的上一个值考虑的最后y值是{em>开始搜索值的下一个值{{ 1}}。这导致版本4

y

允许for x in 1..N { y = x+1 z = y+1 while z <= N { while z * z < x * x + y * y { z = z + 1 } if z * z == x * x + y * y and z <= N then { // use x, y, z } y = y + 1 } } y仅“扫描”z以上的值一次。它不仅比x 1000快100多倍,而且在N上是二次方,因此加速随着N的增长而增加。

我经常遇到这种改进,经常不信任“计数循环”,除了最简单的用途(例如遍历数组)。

更新:显然我应该指出一些容易被忽视的关于V4的事情。

  1. N循环的两个都由while的值控制(一个直接,另一个通过z的平方间接控制) 。内部z实际上正在加速外部while,而不是与它正交。 了解循环的作用非常重要,而不仅仅是计算循环次数。

  2. V4中的所有计算都是严格的整数运算。相比之下,转换到浮点或从浮点计算转换成本很高。

  3. V4在常量内存中运行,只需要三个整数变量。没有要分配和初始化的数组或散列表(并且可能导致内存不足错误)。

  4. 原始问题允许所有whilexy在同一范围内变化。 V1..V4遵循该模式。

  5. 下面是一组非常科学的时序(在我的旧笔记本电脑上使用Eclipse下运行其他东西的Java ...),其中“使用x,y,z”是通过实例化一个Triple对象来实现的。这三个值并将其放入ArrayList中。 (对于这些运行,x设置为10,000,每种情况下产生12,471个三元组。)

    N

    “数组和地图”算法基本上是

    Version 4:           46 sec.
    using square root:  134 sec.
    array and map:      400 sec.
    

    “使用平方根”算法基本上是

    squares = array of i*i for i in 1 .. N
    roots = map of i*i -> i for i in 1 .. N
    for x in 1 .. N
        for y in x+1 .. N
            z = roots[squares[x] + squares[y]]
            if z exists use x, y, z
    

    V4的实际代码是:

    for x in 1 .. N
        for y in x+1 .. N
            z = (int) sqrt(x * x + y * y)
            if z * z == x * x + y * y then use x, y, z
    

    请注意,在外部循环中计算public Collection<Triple> byBetterWhileLoop() { Collection<Triple> result = new ArrayList<Triple>(limit); for (int x = 1; x < limit; ++x) { int xx = x * x; int y = x + 1; int z = y + 1; while (z <= limit) { int zz = xx + y * y; while (z * z < zz) {++z;} if (z * z == zz && z <= limit) { result.add(new Triple(x, y, z)); } ++y; } } return result; } (尽管我没有费心去缓存x * x);在其他变体中也进行了类似的优化。

    我很乐意根据请求提供Java源代码,以便在我错误实现任何内容的情况下为其他变体提供。

答案 1 :(得分:40)

到目前为止,它比任何解决方案都要快得多。通过三元树找到三胞胎。

  

Wolfram说:

     霍尔(1970年)和罗伯茨(1977年)证明这是一个原始的毕达哥拉斯三重奏,当且仅当

     

(a,b,c)=(3,4,5)M

     

其中M是矩阵U,A,D的有限乘积。

我们有一个公式来生成每个原始三元组。

在上面的公式中,斜边不断增长,因此检查最大长度非常容易。

在Python中:

import numpy as np

def gen_prim_pyth_trips(limit=None):
    u = np.mat(' 1  2  2; -2 -1 -2; 2 2 3')
    a = np.mat(' 1  2  2;  2  1  2; 2 2 3')
    d = np.mat('-1 -2 -2;  2  1  2; 2 2 3')
    uad = np.array([u, a, d])
    m = np.array([3, 4, 5])
    while m.size:
        m = m.reshape(-1, 3)
        if limit:
            m = m[m[:, 2] <= limit]
        yield from m
        m = np.dot(m, uad)

如果您喜欢所有三元组而不仅仅是原语:

def gen_all_pyth_trips(limit):
    for prim in gen_prim_pyth_trips(limit):
        i = prim
        for _ in range(limit//prim[2]):
            yield i
            i = i + prim

list(gen_prim_pyth_trips(10**4))需要2.81毫秒才能返回1593个元素,而list(gen_all_pyth_trips(10**4))需要19.8毫秒才能返回12471个元素

作为参考,accepted answer (in python)为12471个元素花费了38秒。

只是为了好玩,将上限设置为一百万list(gen_all_pyth_trips(10**6)),在2.66秒内返回1980642元素(3秒内几乎200万三倍)。 list(gen_all_pyth_trips(10**7))使我的计算机瘫痪,因为列表变得如此之大,它消耗了最后一点ram。像sum(1 for _ in gen_all_pyth_trips(10**7))这样的事情绕过了这个限制,并在30秒内返回23471475个元素。

有关所用算法的详细信息,请查看WolframWikipedia上的文章。

答案 2 :(得分:13)

你应该定义x&lt; y&lt; ž。

for x in range (1, 1000):
    for y in range (x + 1, 1000):
            for z in range(y + 1, 1000):

另一个好的优化是仅使用x和y并计算zsqr = x * x + y * y。如果zsqr是一个平方数(或z = sqrt(zsqr)是整数),则它是三元组,否则不是。这样,您只需要两个循环而不是三个循环(例如,大约快了1000倍)。

答案 3 :(得分:11)

之前列出的生成Pythagorean triplets的算法是从基本关系a^2 + b^2 = c^2派生的朴素方法的所有修改,其中(a, b, c)是正整数的三元组。事实证明,毕达哥拉斯三胞胎满足了一些相当显着的关系,可以用来生成所有毕达哥拉斯三胞胎。

Euclid发现了第一个这样的关系。他确定,对于每个毕达哥拉斯三重(a, b, c),可能在重新排序ab之后,有mn m > nk其中至少有一个是偶数,而正整数a = k (2mn) b = k (m^2 - n^2) c = k (m^2 + n^2) 就是

m

然后生成毕达哥拉斯三元组,生成不同奇偶校验的相对正整数nk,以及正整数struct PythagoreanTriple { public int a { get; private set; } public int b { get; private set; } public int c { get; private set; } public PythagoreanTriple(int a, int b, int c) : this() { this.a = a < b ? a : b; this.b = b < a ? a : b; this.c = c; } public override string ToString() { return String.Format("a = {0}, b = {1}, c = {2}", a, b, c); } public static IEnumerable<PythagoreanTriple> GenerateTriples(int max) { var triples = new List<PythagoreanTriple>(); for (int m = 1; m <= max / 2; m++) { for (int n = 1 + (m % 2); n < m; n += 2) { if (m.IsRelativelyPrimeTo(n)) { for (int k = 1; k <= max / (m * m + n * n); k++) { triples.Add(EuclidTriple(m, n, k)); } } } } return triples; } private static PythagoreanTriple EuclidTriple(int m, int n, int k) { int msquared = m * m; int nsquared = n * n; return new PythagoreanTriple(k * 2 * m * n, k * (msquared - nsquared), k * (msquared + nsquared)); } } public static class IntegerExtensions { private static int GreatestCommonDivisor(int m, int n) { return (n == 0 ? m : GreatestCommonDivisor(n, m % n)); } public static bool IsRelativelyPrimeTo(this int m, int n) { return GreatestCommonDivisor(m, n) == 1; } } class Program { static void Main(string[] args) { PythagoreanTriple.GenerateTriples(1000).ToList().ForEach(t => Console.WriteLine(t)); } } 并应用上述公式。

{{1}}

关于Formulas for generating Pythagorean triples的维基百科文章包含其他此类公式。

答案 4 :(得分:8)

可以针对速度,内存使用,简单性等方面调整算法。

这是一个针对速度而调整的pythagore_triplets算法,代价是内存使用和简单性。如果你想要的只是速度,这可能就是你要走的路。

list(pythagore_triplets(10000))的计算在我的计算机上需要40秒,而ΤΖΩΤΖΙΟΥ算法需要63秒,并且可能需要几天计算Tafkas的算法(以及使用3个嵌入式循环而不仅仅是2个的所有其他算法)。

def pythagore_triplets(n=1000):
   maxn=int(n*(2**0.5))+1 # max int whose square may be the sum of two squares
   squares=[x*x for x in xrange(maxn+1)] # calculate all the squares once
   reverse_squares=dict([(squares[i],i) for i in xrange(maxn+1)]) # x*x=>x
   for x in xrange(1,n):
     x2 = squares[x]
     for y in xrange(x,n+1):
       y2 = squares[y]
       z = reverse_squares.get(x2+y2)
       if z != None:
         yield x,y,z

>>> print list(pythagore_triplets(20))
[(3, 4, 5), (5, 12, 13), (6, 8, 10), (8, 15, 17), (9, 12, 15), (12, 16, 20)]

请注意,如果您要计算前十亿个三元组,那么由于内存不足错误,此算法在启动之前会崩溃。因此,对于高值n,ΤΖΩΤΖΙΟΥ的算法可能是更安全的选择。

顺便说一句,这是Tafkas的算法,为了我的性能测试而翻译成python。它的缺陷是需要3个循环而不是2个循环。

def gcd(a, b):
  while b != 0:
    t = b
    b = a%b
    a = t
  return a

def find_triple(upper_boundary=1000):
  for c in xrange(5,upper_boundary+1):
    for b in xrange(4,c):
      for a in xrange(3,b):
        if (a*a + b*b == c*c and gcd(a,b) == 1):
          yield a,b,c

答案 5 :(得分:6)

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算法具有单调递增的x值。

修改

看来这个问题还活着:) 自从我回来并重新访问代码之后,我尝试了第二种方法,这几乎是我之前建议的4倍(大约26%的CPU时间为N = 10000),因为它避免了大量不必要的计算:

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)]

请注意,此算法的值增加z

如果算法转换为C -where,更接近金属,乘法比加法需要更多的时间 - 考虑到连续正方形之间的步长为:

,可以将必要的乘法最小化
  

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

因此所有内部x2= x*xy2= y*y都会转换为加法和减法,如下所示:

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

当然,在Python中,与版本2相比,生成的额外字节码实际上减慢了算法,但我敢打赌(不检查:) V.3在C中更快。

为每个人欢呼:)

答案 6 :(得分:4)

我对Kyle Gullion的回答进行了扩展,以便将三元组分类为hypothenuse,然后是最长的一侧。

它不使用numpy,但需要SortedCollection(或SortedList),例如this one

def primitive_triples():
""" generates primitive Pythagorean triplets x<y<z
sorted by hypotenuse z, then longest side y
through Berggren's matrices and breadth first traversal of ternary tree
:see: https://en.wikipedia.org/wiki/Tree_of_primitive_Pythagorean_triples
"""
key=lambda x:(x[2],x[1])
triples=SortedCollection(key=key)
triples.insert([3,4,5])
A = [[ 1,-2, 2], [ 2,-1, 2], [ 2,-2, 3]]
B = [[ 1, 2, 2], [ 2, 1, 2], [ 2, 2, 3]]
C = [[-1, 2, 2], [-2, 1, 2], [-2, 2, 3]]

while triples:
    (a,b,c) = triples.pop(0)
    yield (a,b,c)

    # expand this triple to 3 new triples using Berggren's matrices
    for X in [A,B,C]:
        triple=[sum(x*y for (x,y) in zip([a,b,c],X[i])) for i in range(3)]
        if triple[0]>triple[1]: # ensure x<y<z
            triple[0],triple[1]=triple[1],triple[0]
        triples.insert(triple)

def triples():
""" generates all Pythagorean triplets triplets x<y<z 
sorted by hypotenuse z, then longest side y
"""
prim=[] #list of primitive triples up to now
key=lambda x:(x[2],x[1])
samez=SortedCollection(key=key) # temp triplets with same z
buffer=SortedCollection(key=key) # temp for triplets with smaller z
for pt in primitive_triples():
    z=pt[2]
    if samez and z!=samez[0][2]: #flush samez
        while samez:
            yield samez.pop(0)
    samez.insert(pt)
    #build buffer of smaller multiples of the primitives already found
    for i,pm in enumerate(prim):
        p,m=pm[0:2]
        while True:
            mz=m*p[2]
            if mz < z:
                buffer.insert(tuple(m*x for x in p))
            elif mz == z: 
                # we need another buffer because next pt might have
                # the same z as the previous one, but a smaller y than
                # a multiple of a previous pt ...
                samez.insert(tuple(m*x for x in p))
            else:
                break
            m+=1
        prim[i][1]=m #update multiplier for next loops
    while buffer: #flush buffer
        yield buffer.pop(0)
    prim.append([pt,2]) #add primitive to the list

代码位于math2 modulemy Python library。它针对OEIS的一些系列进行了测试(底部的代码here),这使我能够find a mistake in A121727: - )

答案 7 :(得分:2)

我在Ruby中编写了该程序,它类似于python实现。重要的一点是:

if x*x == y*y + z*z && gcd(y,z) == 1:

然后你必须实现一个返回两个给定数字的最大公约数(gcd)的方法。 Ruby中的一个非常简单的例子:

def gcd(a, b)
    while b != 0
      t = b
      b = a%b
      a = t
    end
    return a
end

找到三胞胎的完整Ruby方法将是:

def find_triple(upper_boundary)

  (5..upper_boundary).each {|c|
    (4..c-1).each {|b|
      (3..b-1).each {|a|
        if (a*a + b*b == c*c && gcd(a,b) == 1)
          puts "#{a} \t #{b} \t #{c}"
        end
      }
    }
  }
end

答案 8 :(得分:1)

在python中,我们可以将所有数字的平方存储在另一个列表中。 然后找到给定的所有数字对的排列 平方它们 最后检查任何一对平方和是否与平方列表匹配

答案 9 :(得分:1)

是的,有。

好的,现在你想知道原因。为什么不限制它以便z> ÿ?试试

for z in range (y+1, 1000)

答案 10 :(得分:1)


for a in range(1,20):
    for b in range(1,20):
        for c in range(1,20):
            if a>b and c and c>b:
                if a**2==b**2+c**2:
                    print("triplets are:",a,b,c)

答案 11 :(得分:1)

from  math import sqrt
from itertools import combinations

#Pythagorean triplet - a^2 + b^2 = c^2 for (a,b) <= (1999,1999)
def gen_pyth(n):
if n >= 2000 :
  return
ELEM =   [  [ i,j,i*i + j*j ] for i , j in list(combinations(range(1, n +   1 ), 2)) if sqrt(i*i + j*j).is_integer() ]
print (*ELEM , sep = "\n")


gen_pyth(200)

答案 12 :(得分:1)

旧问题,但我仍会输入我的东西。 有两种生成独特的毕达哥拉斯三元组的一般方法。一个是通过缩放,另一个是使用这个古老的公式。

什么缩放基本上需要一个常数n,然后乘以一个基本三元组,比如说3,4,5乘以n。所以将n设为2,我们得到6,8,10我们的下一个三联。

<强>缩放

def pythagoreanScaled(n):
    triplelist = []
    for x in range(n):
        one = 3*x
        two = 4*x
        three = 5*x
        triple = (one,two,three)
        triplelist.append(triple)
return triplelist

公式方法使用的事实是,如果我们取一个数x,计算2m,m ^ 2 + 1和m ^ 2-1,那三个将永远是毕达哥拉斯三元组。

<强>式

def pythagoreantriple(n):
    triplelist = []
    for x in range(2,n):
        double = x*2
        minus = x**2-1
        plus = x**2+1
        triple = (double,minus,plus)
        triplelist.append(triple)
    return triplelist

答案 13 :(得分:0)

应该注意的是,对于a,b和c,您不需要一直循环到N.

对于a,您只需要从1循环到int(sqrt(n**2/2))+1,对于b,a+1int(sqrt(n**2-a**2))+1,对于从int(sqrt(a**2+b**2)int(sqrt(a**2+b**2)+2的c循环

答案 14 :(得分:0)

# To find all pythagorean triplets in a range
import math
n = int(input('Enter the upper range of limit'))
for i in range(n+1):
    for j in range(1, i):
        k = math.sqrt(i*i + j*j)
        if k % 1 == 0 and k in range(n+1):
            print(i,j,int(k))

答案 15 :(得分:0)

您可以尝试

  triplets=[]
    for a in range(1,100):
        for b in range(1,100):
            for c in range(1,100):
                if  a**2 + b**2==c**2:
                    i=[a,b,c]
                    triplets.append(i)
                    for i in triplets:
                          i.sort()
                          if triplets.count(i)>1:
                              triplets.remove(i)
    print(triplets)

答案 16 :(得分:0)

您必须使用欧几里得的毕达哥拉斯三胞胎证明。请在下面...

U可以选择大于零的任意数字,例如m,n

根据Euclid,三元组将是a(m*m-n*n)b(2*m*n)c(m*m+n*n)

现在应用这个公式找出三胞胎,说我们的三胞胎的值是6,那么另外两个呢?好,让我们解决...

a(m*m-n*n)b(2*m*n)c(m*m+n*n)

确定b(2*m*n)显然是偶数。所以现在

(2*m*n)=6 =>(m*n)=3 =>m*n=3*1 =>m=3,n=1

U可以采用除3和1以外的任何其他值,但是这两个值应包含两个数字的乘积3 (m*n=3)

现在,当m=3n=1之后,

a(m*m-n*n)=(3*3-1*1)=8c(m*m-n*n)=(3*3+1*1)=10

6,8,10是我们的三元组,这是我们如何生成三元组的可视化。

如果给定的数字像(9)一样是奇数,则在此处稍作修改,因为b(2*m*n)

永远不会是奇数。所以,这里我们必须采取

a(m*m-n*n)=7(m+n)*(m-n)=7*1(m+n)=7(m-n)=1

现在从此处找到m和n,然后找到其他两个值。

如果您不理解,请仔细阅读。

按照此代码进行编码,它将有效地生成不同的三元组。

答案 17 :(得分:0)

只是检查,但我一直在使用以下代码制作毕达哥拉斯三元组。这是非常快的(我已经尝试了一些这里的例子,虽然我有点学习它们并自己编写并回来检查这里(2年前))。我认为这段代码正确地找到所有毕达哥拉斯三元组(命名你的极限)并且相当快。我用C ++来制作它。

ullong是unsigned long long,我创建了几个square和root函数 我的root函数基本上说如果给定数字的平方根(在使它成为整数(整数)之后)平方不等于数给予然后返回-1因为它不是可root的。 _square和_root如上所述按预期执行,我知道另一种优化方法,但我还没有做过,也没有测试过。

generate(vector<Triple>& triplist, ullong limit) {
cout<<"Please wait as triples are being generated."<<endl;
register ullong a, b, c;
register Triple trip;
time_t timer = time(0);

for(a = 1; a <= limit; ++a) {
    for(b = a + 1; b <= limit; ++b) {
        c = _root(_square(a) + _square(b));

        if(c != -1 && c <= limit) {
            trip.a = a; trip.b = b; trip.c = c;

            triplist.push_back(trip);

        } else if(c > limit)
            break;
    }
}

timer = time(0) - timer;
cout<<"Generated "<<triplist.size()<<" in "<<timer<<" seconds."<<endl;
cin.get();
cin.get();

}

让我知道你们都在想什么。它根据我转过身来的老师生成所有原始和非原始三元组。 (如果我没记错的话,她会把它测试到100)。

前一个编码器提供的v4的结果是

下面是一组非常科学的时序(在我的旧笔记本电脑上使用Eclipse下运行其他东西的Java ...),其中“使用x,y,z”是通过实例化一个Triple对象来实现的。这三个值并将其放入ArrayList中。 (对于这些运行,N设置为10,000,在每种情况下产生12,471三倍。)

第4版:46秒 使用平方根:134秒。 数组和地图:400秒。

我的结果是 生成多少三倍:10000

请等待生成三元组。 在2秒内生成12471。

那是在我开始通过编译器进行优化之前。 (我记得先前有10000到0秒,有很多特殊选项和东西)。我的代码也会生成所有三元组,其中100,000为高限制1,2,可以在3.2分钟内完成(我认为1,000,000限制需要一个小时)。

我稍微修改了代码并将10,000限制降低到1秒(没有优化)。最重要的是,经过仔细考虑,我可以分解成块并在给定范围内进行线程化(例如,100,000个分成4个相等的块,用于3个cpu(1个额外的,希望消耗cpu时间以防万一),范围为1到25,000 (从1开始,限制为25,000),25,000到50,000,50,000到75,000,以及75,000结束。我可以这样做,看看它是否加速了(我将预制线程,不包括实际数量)时间来执行三重函数。我需要一个更精确的计时器和一种连接向量的方法。我认为如果1个3.4 GHZ cpu和8 gb ram处理它可以在1秒内完成10,000作为lim,然后是3 cpus应该在1/3秒内做到这一点(并且我按原样转向更高的秒)。

答案 18 :(得分:0)

Hall / Roberts方法的非数字化版本是

def pythag3(limit=None, all=False):
    """generate Pythagorean triples which are primitive (default)
    or without restriction (when ``all`` is True). The elements
    returned in the tuples are sorted with the smallest first.

    Examples
    ========

    >>> list(pythag3(20))
    [(3, 4, 5), (8, 15, 17), (5, 12, 13)]
    >>> list(pythag3(20, True))
    [(3, 4, 5), (6, 8, 10), (9, 12, 15), (12, 16, 20), (8, 15, 17), (5, 12, 13)]

    """
    if limit and limit < 5:
        return
    m = [(3,4,5)]  # primitives stored here
    while m:
        x, y, z = m.pop()
        if x > y:
            x, y = y, x
        yield (x, y, z)
        if all:
            a, b, c = x, y, z
            while 1:
                c += z
                if c > limit:
                    break
                a += x
                b += y
                yield a, b, c
        # new primitives
        a = x - 2*y + 2*z, 2*x - y + 2*z, 2*x - 2*y + 3*z
        b = x + 2*y + 2*z, 2*x + y + 2*z, 2*x + 2*y + 3*z
        c = -x + 2*y + 2*z, -2*x + y + 2*z, -2*x + 2*y + 3*z
        for d in (a, b, c):
            if d[2] <= limit:
                m.append(d)

它比numpy编码的版本慢,但是在我的慢速计算机上大约需要1.4秒的时间来生成最大元素小于或等于10^6的基元。 (而且列表m从未超过18个元素。)

答案 19 :(得分:0)

Joel Neely的第5版。

因为X可以是'N-2'的最大值,并且对于1..N的范围,Y可以是'N-1'的最大值。由于Z max为N且Y max为N-1,因此X可以是Sqrt(N * N - (N-1)*(N-1))= Sqrt(2 * N - 1)的最大值,并且可以从3开始

MaxX = ( 2 * N - 1 ) ** 0.5

for x in 3..MaxX {
  y = x+1
  z = y+1
  m = x*x + y*y
  k = z * z
  while z <= N {
     while k < m {
        z = z + 1
        k = k + (2*z) - 1
    }
    if k == m and z <= N then {
        // use x, y, z
    }
    y = y + 1
    m = m + (2 * y) - 1
  }
 }