How does the Euclidean Algorithm work?

前端 未结 5 665
误落风尘
误落风尘 2020-12-08 23:12

I just found this algorithm to compute the greatest common divisor in my lecture notes:

public static int gcd( int a, int b ) {
    while (b != 0) {
                 


        
相关标签:
5条回答
  • 2020-12-08 23:40

    They're equivalent. First thing to notice is that q in the second program is not used at all. The other difference is just iteration vs. recursion.

    As to why it works, the Wikipedia page linked above is good. The first illustration in particular is effective to convey intuitively the "why", and the animation below then illustrates the "how".

    0 讨论(0)
  • 2020-12-08 23:40

    given that 'q' is never used, I don't see a difference between your plain iterative function, and the recursive iterative function... both do

    gdc(first number, second number)
      as long as (second number > 0) {
          int remainder = first % second;
          gcd = try(second as first, remainder as second);
      }
    }
    

    Barring trying to apply this to non-integers, under which circumstances does this algorithm fail?

    (also see http://en.wikipedia.org/wiki/Euclidean_algorithm for lots of detailed info)

    0 讨论(0)
  • 2020-12-08 23:50

    The Wikipedia article contains an explanation, but it's not easy to find it immediately (also, procedure + proof don't always answer the question "why it works").

    Basically it comes down to the fact that for two integers a, b (assuming a >= b), it is always possible to write a = bq + r where r < b.

    If d=gcd(a,b) then we can write a=ds and b=dt. So we have ds = qdt + r. Since the left hand side is divisible by d, the right hand side must also be divisible by d. And since qdt is divisible by d, the conclusion is that r must also be divisible by d.

    To summarise: we have a = bq + r where r < b and a, b and r are all divisible by gcd(a,b).

    Since a >= b > r, we have two cases:

    1. If r = 0 then a = bq, and so b divides both b and a. Hence gcd(a,b)=b.
    2. Otherwise (r > 0), we can reduce the problem of finding gcd(a,b) to the problem of finding gcd(b,r) which is exactly the same number (as a, b and r are all divisible by d).

    Why is this a reduction? Because r < b. So we are dealing with numbers that are definitely smaller. This means that we only have to apply this reduction a finite number of times before we reach r = 0.

    Now, r = a % b which hopefully explains the code you have.

    0 讨论(0)
  • 2020-12-08 23:50

    Here is a very useful explanation that I found.

    For those too lazy to open it, this is what it says :

    Consider the example when you had to find the GCD of (3084,1424). Lets assume that d is the GCD. Which means d | 3084 and d | 1424 (using the symbol '|' to say 'divides').

    It follows that d | (3084 - 1424). Now we'll try to reduce these numbers which are divisible by d (in this case 3084 and 1024) as much as possible, so that we reach 0 as one of the numbers. Remember that GCD (a, 0) is a.

    Since d | (3084 - 1424), it follows that d | ( 3084 - 2(1424) ) which means d | 236.
    Hint : (3084 - 2*1424 = 236)

    Now forget about the initial numbers, we just need to solve for d, and we know that d is the greatest number that divides 236, 1424 and 3084. So we use the smaller two numbers to proceed because it'll converge the problem towards 0.

    d | 1424 and d | 236 implies that d | (1424 - 236).
    So, d | ( 1424 - 6(236) ) => d | 8.

    Now we know that d is the greatest number that divides 8, 236, 1424 and 3084. Taking the smaller two again, we have

    d | 236 and d | 8, which implies d | (236 - 8).
    So, d | ( 236 - 29(8) ) => d | 4.

    Again the list of numbers divisible by d increases and converges (the numbers are getting smaller, closer to 0). As it stands now, d is the greatest number that divides 4, 8, 236, 1424, 3084.

    Taking same steps,

    d | 8 and d | 4 implies d | (8-4).
    So, d | ( 8 - 2(4) ) => d | 0.

    The list of numbers divisible by d is now 0, 4, 8, 236, 1484, 3084. GCD of (a, 0) is always a. So, as soon as you have 0 as one of the two numbers, the other number is the gcd of original two and all those which came in between.

    This is exactly what your code is doing. You can recognize the terminal condition as GCD (a, 0) = a.

    The other step is to find the remainder of the two numbers, and choose that and the smaller of the previous two as the new numbers.

    0 讨论(0)
  • 2020-12-09 00:00

    Here is an interesting blog post: Tominology.

    Where a lot of the intuition behind the Euclidean Algorithm is discussed, it is implemented in JavaScript, but I believe that if one want's there is no difficult to convert the code to Java.

    0 讨论(0)
提交回复
热议问题