1

So my program tries to find Pythagorean Triplet, where a^2 + b^2 = c^2 AND a+b+c=1000. So everything works well, but program finds the answer quite early in the program runtime, so I would like to break somehow out of all the loops. I am trying simple boolean method, but for some reason my cycle stops after 1 second. If I remove exit = True then everything works (but no break obviously).

P.s. it's also same problem if I use simple 0 or 1 integers to check that. Can anyone give me ideas why this is not working?

i = 0
j = 0
k = 0
exit = False
while (i < 999 and exit == False):
    while (j < 999 and exit == False):
        while (k < 999 and exit == False):
            if i*i + j*j == k*k:                        
                if i + j + k == 1000:
                    exit = True
                    ii = i
                    jj = j
                    kk = k
            k += 1
        j += 1
        k = 1
    i += 1
    j = 1
i = 1
print('result: %d^2 + %d^2 = %d^2' % (ii, jj, kk))
user3763437
  • 359
  • 2
  • 10
  • 2
    Holy nested loops! I'd use `for` loops for this anyway, and you can use an *exception* to break out of a set of loops fast. – Martijn Pieters Jul 10 '14 at 21:58
  • 6
    Or simply wrap this in a function and `return` – C.B. Jul 10 '14 at 21:59
  • I know that there are other methods for achieving same goal, but why is this exact thing not working I am wondering. But thanks for ideas. – user3763437 Jul 10 '14 at 22:00
  • 2
    You don't need the loop for `k`; `k = 1000 - i - j`. – Martijn Pieters Jul 10 '14 at 22:01
  • OP, it seems you are solving project euler. As usual, there is a better way to generate pythagorean triplets, as you can see [here](http://en.wikipedia.org/wiki/Pythagorean_triple#Generating_a_triple). – Lucas Virgili Jul 10 '14 at 22:01
  • You are initializing `i`, `j`, and `k` somewhere prior to your `while` loop, right? – Peter DeGlopper Jul 10 '14 at 22:02
  • Does this even work without an error? You're defining your variables after the relevant while loop –  Jul 10 '14 at 22:02
  • Ok guys, I it's not efficient, etc, I am just learning programming, but why is this simple check not working? – user3763437 Jul 10 '14 at 22:02
  • Closely related, possible dupe: [Generating unique, ordered Pythagorean triplets](http://stackoverflow.com/q/575117) and [What is the best way to generate Pythagorean triples?](http://stackoverflow.com/q/22821210) – Martijn Pieters Jul 10 '14 at 22:03
  • Yes, I initialize i, j and k, and it solves the problem, but I need to wait until it finishes running all the cycles. – user3763437 Jul 10 '14 at 22:04
  • I tried this code with `i`, `j`, and `k` initialized to 1 and it exited as desired. With a `print` for every increment to `i`, `j`, or `k`, one for spotting the exit, and one for reporting the actual result it wrote 198777652 lines out of the 994011994 for the non-exit solution (998 * 998 * 988 + 1 + 1 for exiting and answer). – Peter DeGlopper Jul 10 '14 at 22:12
  • @PeterDeGlopper yep, the problem was that I initialized to 0, stupid mistake. – user3763437 Jul 10 '14 at 22:24
  • I see your problem is solved - one style note is that it's not considered Pythonic to compare to boolean values directly (`exit == False`). Instead, you'd usually write `while i < 999 and not exit:`. With parens to taste. – Peter DeGlopper Jul 10 '14 at 22:25
  • @PeterDeGlopper gotcha, changed my code how you said :) – user3763437 Jul 10 '14 at 22:36

5 Answers5

2

The specific problem you have is simply that your code does meet the criteria you set, when

ii == 0
jj == 500
kk == 500

If you don't want this trivial solution, you should initialise to 1 at the start (or, better, spot the trivial opportunity to factor out duplication and set e.g. j = 1 in only one place).

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
  • Yes, initializing counters to 1 solved the issue, but I still don't understand your explanation on what is wrong :p – user3763437 Jul 10 '14 at 22:10
  • @user3763437 what do you mean you don't understand? It was wrong because you started with `i == 0`, which gave a trivial solution you didn't want. – jonrsharpe Jul 10 '14 at 22:11
2

Make it a Generator Function:

>>> def pythagorean_triangles(target):
...     for a in range(1, target):
...         for b in range(1, target):
...             for c in range(1, target):
...                 if a ** 2 + b ** 2 == c ** 2 and a + b + c == target:
...                     yield a, b, c
...
>>> triangles = pythagorean_triangles(1000)
>>> next(triangles)
(200, 375, 425)
pillmuncher
  • 10,094
  • 2
  • 35
  • 33
1

Functions are a great way to do this early exit logic. I've also switched your loops to use the xrange() builtin, which cleans up some of your surrounding logic.

def triplet():
    for i in xrange(1000):
        for j in xrange(1000):
            for k in xrange(1000):
                if i*i + j*j == k*k:                    
                    if i + j + k == 1000:
                        return (i, j, k)

i, j, k = triplet()
print('result: %d^2 + %d^2 = %d^2' % (i, j, k))

Note that from here, there's a number of optimizations that you can make.

  • Like that given an i and j, you only need to test one k, that is k == 1000 - i - j.
  • Like that if you've tested i == 1 and j == 2, you don't need to test i == 2 and j == 1. They will have the same result.

Additionally, if you wanted to skip 0 in the loop, you could do xrange(1, 1000). xrange() allows you to pass a start and an end position.

Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
0

Why not simply using a pythonic way to solve the problem:

[(a,b,c) for a,b,c in itertools.product(range(0,999), repeat=3) if (a**2 + b**2 == c**2) and (a + b + c == 1000)]
mateuszk87
  • 143
  • 11
0

You have already been suggested how to refactor the code to avoid the need to break loops in the first place, and personally I would use a generator function solution of @pillmuncher (if still considering the use of loops at all).

Here is just an example of how you can break a loop without using a boolean flag:

i = 1
while i < 999:
    j = 1
    while j < 999:
        k = 1
        while k < 999:
            if i*i + j*j == k*k and i + j + k == 1000:
                ii, jj, kk = i, j, k
            else:
                k += 1
                continue
            break
        else:
            j += 1
            continue
        break
    else:
        i += 1
        continue
    break
print('result: %d^2 + %d^2 = %d^2' % (ii, jj, kk))

Or, using more neat for ... in range(...) (or better xrange in Python 2) loop:

for i in range(1, 999):
    for j in range(1, 999):
        for k in range(1, 999):
            if i*i + j*j == k*k and i + j + k == 1000:
                ii, jj, kk = i, j, k
            else:
                continue
            break
        else:
            continue
        break
    else:
        continue
    break
print('result: %d^2 + %d^2 = %d^2' % (ii, jj, kk))
Community
  • 1
  • 1
Eldar Abusalimov
  • 24,387
  • 4
  • 67
  • 71