Thuật toán Euclide (để tìm ước số chung lớn nhất)


22

Các thách thức

Viết một chương trình hoặc chức năng mà phải mất hai số nguyên đầu vào, ij, và kết quả đầu ra ước chung lớn nhất của họ; được tính bằng cách sử dụng thuật toán Euclide (xem bên dưới).


Đầu vào

Đầu vào có thể được lấy dưới dạng đại diện chuỗi được phân tách bằng dấu cách ijhoặc là hai số nguyên riêng biệt. Bạn có thể giả định rằng số nguyên sẽ nhỏ hơn hoặc bằng 10.000. Bạn cũng có thể giả định rằng các số nguyên đầu vào sẽ không là số nguyên tố với nhau.


Sự cố Euclide

Số lớn hơn giữa ijđược chia cho càng nhỏ càng nhiều lần càng tốt. Sau đó, phần còn lại được thêm vào. Quá trình này được lặp lại với phần còn lại và số trước đó, cho đến khi phần còn lại trở thành 0.

Ví dụ: nếu đầu vào là 1599 650:

1599 = (650 * 2) + 299
 650 = (299 * 2) +  52
 299 =  (52 * 5) +  39
  52 =  (39 * 1) +  13
  39 =  (13 * 3) +   0

Số cuối cùng 13, là ước số chung lớn nhất của hai số nguyên đầu vào. Nó có thể được hình dung như thế này:


Đầu ra

Đầu ra của bạn phải là bảng phân tích theo mẫu ở trên, theo sau là dòng mới và GCD. Nó có thể được đầu ra thông qua bất kỳ phương tiện.


Ví dụ

Đầu vào

18 27
50 20
447 501
9894 2628

Đầu ra

27 = (18 * 1) + 9
18 =  (9 * 2) + 0
9

50 = (20 * 2) + 10
20 = (10 * 2) +  0
10

501 = (447 * 1) + 54
447 =  (54 * 8) + 15
 54 =  (15 * 3) +  9
 15 =   (9 * 1) +  6
  9 =   (6 * 1) +  3
  6 =   (3 * 2) +  0
3

9894 = (2628 *  3) + 2010
2628 = (2010 *  1) +  618
2010 =  (618 *  3) +  156
 618 =  (156 *  3) +  150
 156 =  (150 *  1) +    6
 150 =    (6 * 25) +    0
6

Lưu ý: Đầu ra không phải cách nhau như trên. Khoảng cách chỉ cho rõ ràng. Dấu ngoặc đơn là bắt buộc.


Tiền thưởng

Nếu đầu ra của bạn được đặt cách nhau như trên, bạn có thể thêm phần thưởng -10% vào điểm số của mình.


1. Chúng ta có thể giả sử số lớn nhất được đưa ra đầu tiên không? 2. Đối với phần thưởng, bạn có nghĩa là độ rộng trường phải không đổi và chỉ đủ để cho phép một khoảng trắng trước số lớn nhất? (với các khoảng trắng đến trước dấu ngoặc trái trong cột số thứ hai.) Bạn nên tránh các cụm từ mơ hồ như "như chúng ở trên" khi đầu ra là biến. Không sao nếu đầu ra yêu cầu được cố định.
Cấp sông St

Ok tôi thấy một số ví dụ có số thứ hai lớn nhất
Level River St

Tiêu đề ban đầu của bạn là OK, tôi đã nhận xét về những gì đã xảy ra tại meta.codegolf.stackexchange.com/q/7043/15599 . Tuy nhiên, cụm từ "mẫu số chung lớn nhất" đã sai. "Mẫu số" liên quan đến phân số. Googling "mẫu số chung lớn nhất" chỉ đưa ra kết quả cho "ước số / nhân tố chung lớn nhất".
Cấp sông St

Tôi nghĩ rằng tiêu đề là ổn, nhưng tôi đã đổi nó thành "The" để không làm hài lòng bất cứ ai. Cảm ơn bạn đã chỉnh sửa trong "ước số", BTW. @steveverrill
Zach Gates

Câu trả lời:


4

Bình thường, 33 byte

ASQWGs[H\=\(G\*/HG\)\+K%HG)A,KG)H

Dùng thử trực tuyến: Trình diễn hoặc Test Suite

Giải trình:

ASQWGs[H\=\(G\*/HG\)\+K%HG)A,KG)H
  Q                                read the two numbers from input
 S                                 sort them
A                                  and assign them to G and H
   WG                              while G != 0:
                      K%HG           assign H mod G to K
     s[H\=\(G\*/HG\)\+K   )          join the following list items and print:
                                        H=(G*(H/G))+K
                           A,KG      assign K, G to G, H
                               )   end while
                                H  print H

7

CJam, 46 43 39 byte

q~]$3*~\{N5$"=("3$:G'*3$Gmd")+"\}h]7>NG

Hãy thử trực tuyến trong trình thông dịch CJam .

Làm thế nào nó hoạt động

q~]    e# Read all input, evaluate it and wrap the results in an array.
$3*    e# Sort the array and repeat it thrice.
~\     e# Dump the array and swap its last two elements.
{      e# Do:
  N    e#   Push a linefeed.
  5$   e#   Copy the sixth topmost element from the stack.
  "=(" e#   Push that string.
  3$:G e#   Copy the fourth topmost element from the stack. Save it in G.
  '*   e#   Push that character.
  3$   e#   Copy the fourth topmost element from the stack.
  Gmd  e#   Push quotient and remainder of its division by G.
  ")+" e#   Push that string.
  \    e#   Swap the string with the remainder.
}h     e#   If the remainder is positive, repeat the loop.
]7>    e# Wrap the stack in an array and discard its first seven elements.
NG     e# Push a linefeed and G.

6

Con trăn 2, 70

f=lambda a,b:b and'%d=(%d*%d)+%d\n'%(a,b,a/b,a%b)*(a>=b)+f(b,a%b)or`a`

Hàm đệ quy trả về một chuỗi nhiều dòng. Hàm tạo dòng đầu tiên, sau đó nối nó vào kết quả đệ quy với cặp số tiếp theo trong thuật toán Euclide. Khi số thứ hai bằng 0, chúng ta lấy chuỗi của số khác làm trường hợp cơ sở, khiến nó được in trên dòng riêng của nó ở cuối.

Việc định dạng được thực hiện thông qua thay thế chuỗi, sử dụng phép chia số nguyên để lấy bội số.

Một trục trặc cần phải bắt đầu với số lượng lớn hơn được lấy mod, số lượng nhỏ hơn. Thuận tiện, nếu các số theo thứ tự sai, bước đầu tiên của thuật toán Euclidian lật chúng. Để ngăn bước này được hiển thị, chỉ thêm dòng hiện tại nếu số thứ nhất ít nhất là số thứ hai (cần phải có sự bình đẳng f(9,9)).


5

ôi, 78 77

x=$1{for(x<$2?x+=$2-(y=x):y=$2;t=y;x=t)print x"=("y"*"int(x/y)")+",y=x%y}$0=x

Sắp xếp đầu vào theo kích thước cần rất nhiều byte: /
Nó thuộc về điều này:

x=$1;
if(x<$2) x+=$2-(y=x); # add $2 subtract $1 and set y to $1
else y=$2;            # set y to $2

Đầu ra

650 1599 (đầu vào)
1599 = (650 * 2) + 299
650 = (299 * 2) + 52
299 = (52 * 5) + 39
52 = (39 * 1) + 13
39 = (13 * 3) + 0
13

Để giải trí, tôi cũng tạo ra một phiên bản cách đều nhau, cho tôi số điểm 233 * 0,9 == 209,7 byte.

Cập nhật Tôi đã có thể rút ngắn điều này từ 285 byte và bây giờ nó hoạt động với các số dài tùy ý nếu gọi gawk4 với -Mtùy chọn.

x=$1{x<$2?x+=$2-(y=x):y=$2;a=length(x);b=length(y);for(d=length(x%y);t=y;x=t){$++i=x;$++i=y;if(c<l=length($++i=int(x/y)))c=l;$++i=y=x%y}while(j<NF)printf "%"a"d = %"b-length($(j+2))"s(%d * %"c"d) + %"d"d\n",$++j,_,$++j,$++j,$++j}$0=x

Nhưng tôi vẫn có cảm giác mình gặp phải một khối tâm thần nào đó ở đâu đó ...

Đầu ra (gawk4 được gọi với awk -M -f code.awk)

6837125332653632513763 18237983363879361 (đầu vào)
6837125332653632513763 = (18237983363879361 * 374883) + 15415252446024000
     18237983363879361 = (15415252446024000 * 1) + 2822730917855361
     15415252446024000 = (2822730917855361 * 5) + 1301597856747195
      2822730917855361 = (1301597856747195 * 2) + 219535204360971
      1301597856747195 = (219535204360971 * 5) + 203921834942340
       219535204360971 = (203921834942340 * 1) + 15613369418631
       203921834942340 = (15613369418631 * 13) + 948042500137
        15613369418631 = (948042500137 * 16) + 444849416439
          948042500137 = (444849416439 * 2) + 58333667259
          444849416439 = (58333667259 * 7) + 36513745626
           58333667259 = (36513745626 * 1) + 21819921633
           36513745626 = (21819921633 * 1) + 14693823993
           21819921633 = (14693823993 * 1) + 7126097640
           14693823993 = (7126097640 * 2) + 441628713
            7126097640 = (441628713 * 16) + 60038232
             441628713 = (60038232 * 7) + 21361089
              60038232 = (21361089 * 2) + 17316054
              21361089 = (17316054 * 1) + 4045035
              17316054 = (4045035 * 4) + 1135914
               4045035 = (1135914 * 3) + 637293
               1135914 = (637293 * 1) + 498621
                637293 = (498621 * 1) + 138672
                498621 = (138672 * 3) + 82605
                138672 = (82605 * 1) + 56067
                 82605 = (56067 * 1) + 26538
                 56067 = (26538 * 2) + 2991
                 26538 = (2991 * 8) + 2610
                  2991 = (2610 * 1) + 381
                  2610 = (381 * 6) + 324
                   381 = (324 * 1) + 57
                   324 = (57 * 5) + 39
                    57 = (39 * 1) + 18
                    39 = (18 * 2) + 3
                    18 = (3 * 6) + 0
3

Một số dòng mới và các tab được thêm vào

x=$1{
    x<$2?x+=$2-(y=x):y=$2;
    a=length(x);
    b=length(y);
    for(d=length(x%y);t=y;x=t)
    {
        $++i=x;
        $++i=y;
        if(c<l=length($++i=int(x/y)))c=l;
        $++i=y=x%y
    }
    while(j<NF)
        printf "%"a"d = %"b-length($(j+2))"s(%d * %"c"d) + %"d"d\n",
                                               $++j,_,$++j,$++j,$++j
}$0=x

Tôi có thể lưu độ dài của các giá trị ban đầu cho x, y và x% y vào đầu, bởi vì chúng chỉ có thể ngắn hơn mỗi bước. Nhưng đối với yếu tố tôi phải xác định độ dài tối đa trước khi in bất cứ điều gì, bởi vì độ dài của nó có thể thay đổi. Tôi sử dụng $inhư một mảng ở đây, vì nó lưu hai ký tự so với sử dụng [i] mỗi lần.


4

C ++, trình biên dịch GCC, 171 byte (-10%, vì vậy 154 byte)

được rồi, lần thử đầu tiên của tôi ..

#include<iostream>
using namespace std;
int main()
{
    int a,b,c;
    cin>>a>>b;
    if(a<b)
    swap(a,b);
    while(b>0)
    {
        c=a;
        cout<<a<<" = ("<<b<<" * "<<a/b<<") + "<<a%b<<endl;
        a=b;
        b=c%b;
    }
    cout<<a;
}

lời khuyên để mã golf đánh giá cao.

PS Có cần thiết phải đếm byte của tệp tiêu đề chuẩn và int main trong khi sử dụng c ++ không? Loại trừ nó làm giảm 50 byte


Lưu ý: Tôi loại trừ khoảng trắng được sử dụng để làm cho mã đẹp.
Devang Jayachandran

3

T-SQL (2012+), 268 byte

Được triển khai như một hàm bảng nội tuyến thực thi CTE đệ quy. Có thể đáng để cố gắng đưa định dạng vào phần thưởng 10%, nhưng điều đó sẽ phải chờ.

CREATE FUNCTION E(@ INT,@B INT)RETURNS TABLE RETURN WITH M AS(SELECT IIF(@<@B,@B,@)A,IIF(@>@B,@B,@)B),R AS(SELECT A,B,A/B D,A%B R FROM M UNION ALL SELECT B,R,B/R,B%R FROM R WHERE 0<>R)SELECT CONCAT(A,'=(',B,'*',D,')+',R)R FROM R UNION ALL SELECT STR(B)FROM R WHERE R=0

Giải thích và sử dụng:

--Create the function
CREATE FUNCTION E(@ INT,@B INT)RETURNS TABLE RETURN
WITH
    --Order the input correctly
    M AS (
          SELECT IIF(@<@B,@B,@)A,
                 IIF(@>@B,@B,@)B
          )
    --Recursive selection
    ,R AS (
          SELECT A,B,A/B D,A%B R FROM M -- Anchor query
          UNION ALL
          SELECT B,R,B/R,B%R FROM R     -- Recurse until R = 0
          WHERE 0<>R
          )
SELECT CONCAT(A,'=(',B,'*',D,')+',R)R   -- Concat results into output string
FROM R 
UNION ALL                               -- ALL required to maintain order
SELECT STR(B)                           -- Add final number
FROM R WHERE R=0

--Function Usage
SELECT * FROM E(447,501)

R
-----------------------------------------------------
501=(447*1)+54
447=(54*8)+15
54=(15*3)+9
15=(9*1)+6
9=(6*1)+3
6=(3*2)+0
3

2

Rev 1: Ruby, 86

Thuật toán đệ quy, nhờ tiền boa từ Doorknob.

f=->i,j{j>i&&(i,j=j,i)
0<j ?(print i," = (#{j} * #{i/j}) + #{i%j}
";f[j,i%j]):puts(i)}

Rev 0: Ruby, 93

Điều này thực sự đã không làm việc tốt cả. Các whilevòng lặp chiếm quá nhiều ký tự, đặc biệt là với end. Tôi không thể thấy một cách để tránh nó. Đệ quy sẽ yêu cầu một chức năng được đặt tên thay vì lambda, cũng sẽ ăn rất nhiều ký tự.

->i,j{j>i&&(i,j=j,i)
while j>0
print(i," = (#{j} * #{i/j}) + #{i%j}\n")
i,j=j,i%j
end
puts i}

Gọi nó như thế này:

f=->i,j{j>i&&(i,j=j,i)
while j>0
print(i," = (#{j} * #{i/j}) + #{i%j}\n")
i,j=j,i%j
end
puts i}

I=gets.to_i
J=gets.to_i

f.call(I,J)

Mặc dù vậy, bạn có thể sử dụng đệ quy thông qua a=->i,j{...}và gọi aqua a[1,2]Haynot nếu điều này sẽ giúp bạn tiết kiệm các ký tự.
Doorknob

@Doorknob cảm ơn vì tiền boa, tôi không biết cú pháp đó để gọi các hàm lambda (xem cách sử dụng của tôi f.call.) Nó thực sự ngắn hơn một chút, nhưng vẫn còn xa Python.
Cấp sông St

2

PowerShell, 84

Một khối mã đệ quy, được lưu trữ trong một biến. Gọi nó với & $e num1 num2, ví dụ:

$e={$s,$b=$args|Sort;if(!$s){$b}else{$r=$b%$s;"$b=($s*$(($b-$r)/$s))+$r";&$e $s $r}}

PS D:\> & $e 9894 2628
9894=(2628*3)+2010
2628=(2010*1)+618
2010=(618*3)+156
618=(156*3)+150
156=(150*1)+6
150=(6*25)+0
6

Ở dạng dễ đọc hơn, nó thực hiện như sau (nb. Để mã rõ ràng hơn, tôi đã đặt tên lệnh đầy đủ, nhiều khoảng trắng hơn trong chuỗi và làm cho các lệnh đầu ra đường ống rõ ràng):

function Euclid {
    $small, $big = $args|Sort-Object   #Sort argument list, assign to two vars.

    if (!$small) {                     #Recursion end, emit the last
        Write-Output $big              #number alone, for the last line.

    } else {                           #main recursive code

        $remainder = $big % $small
        Write-Output "$big = ( $small* $(($big-$remainder)/$small)) + $remainder"
        Euclid $small $remainder
    }
}

Một phiền toái từ quan điểm của codegolf; PoSh không có phân chia số nguyên, 10/3 trả về Double, nhưng chuyển kết quả thành một số nguyên và nó không luôn luôn làm tròn xuống, nó làm tròn N.5 đến số chẵn gần nhất - lên hoặc xuống. Vì vậy [int](99/2) == 50.

Điều đó để lại hai lựa chọn khó xử:

$remainder = $x % $y
$quotient = [Math]::Floor($x/$y)

# or, worse

$remainder=$null
$quotient = [Math]::DivRem($x, $y, [ref]$remainder)

Đó là lý do tại sao tôi phải đốt một số nhân vật đang làm:

$remainder = $big % $small
($big - $remainder)/$small

Ngoài ra, đó là số lượng

và việc thiếu người vận hành ternary thực sự gây tổn thương.

Tôi cũng có một phiên bản lặp lại, khá độc đáo, cũng có 84 ký tự:

{$r=1;while($r){$s,$b=$args|Sort;$r=$b%$s;"$b=($s*$(($b-$r)/$s))+$r";$args=$s,$r}$s}

Codeblock hoàn toàn ẩn danh, vì vậy hãy chạy nó với

& {*codeblock*} 1599 650

2

PHP, 118 byte

for(list(,$n,$m)=$argv,$g=max($n,$m),$l=min($n,$m);$g;$g=$l,$l=$m)
echo$g,$l?"=($l*".($g/$l^0).")+".($m=$g%$l)."
":"";

Hãy thử trực tuyến!

PHP, 131 byte

for(list(,$n,$m)=$argv,$r=[max($n,$m),min($n,$m)];$r[+$i];)echo$g=$r[+$i],($l=$r[++$i])?"=($l*".($g/$l^0).")+".($r[]=$g%$l)."
":"";

Hãy thử trực tuyến!

-4 byte thay thế list(,$n,$m)=$argvbằng [,$n,$m]=$argvnhu cầu PHP> = 7.1



2

JavaScript (ES6), 74 50 62 61 55 byte

f=(x,y)=>y?y>x?y:x+`=(${y}*${x/y|0})+${x%=y}
`+f(y,x):x
  • Hy sinh 12 byte cho phép các số nguyên được truyền theo bất kỳ thứ tự nào, thay vì lớn nhất trước.

Thử nó

f=(x,y)=>y?y>x?y:x+`=(${y}*${x/y|0})+${x%=y}
`+f(y,x):x
o.innerText=f(i.value=683712533265363251376,j.value=18237983363879361)
i.oninput=j.oninput=_=>o.innerText=f(+i.value,+j.value)
<input id=i type=number><input id=j type=number><pre id=o>


Giải trình

f=          :Assign the function to variable f ...
(x,y)=>     :And take the two integer inputs as arguments via parameters x and y.
y?          :If y is greater than 0 then
y>x?        :    If y is greater than x then
f(y,x)      :        Call f again, with the order of the integers reversed.
            :        (This can only happen the first time the function is called.)
:           :    Else
x           :        Start building the string, beginning with the value of x.
+`=(        :        Append "=(".
${y}        :          The value of y.
*           :          "*"
${x/y|0}    :          The floored value of x divided by y
)+          :          ")+"
${x%=y}     :          The remainder of x divided by y, which is assigned to x
            :          (x%=y is the same as x=x%y.)
\n          :          A newline (a literal newline is used in the solution).
`+f(y,x)    :        Append the value f returns when y and the new value of x
            :        are passed as arguments.
:           :Else
x           :    Return the current value of x,
            :    which will be the greatest common divisor of the original two integers.

1

Mã số 151

a=prompt("g","");b=prompt("l","");c=0;l=[a,b];for(var i=0;i<=1;i++){t=c;o=c+1;r=c+2;n=l[t]%l[o];if(n!==0){l[r]=n;c=c+1;i=0;}else{p=l[o];alert(p);i=2;}}

1

C, 83 byte

g(x,y,z){y&&(printf("%u=(%u*%u)+%u\n",x,y,x/y,z=x%y),z)?g(y,z,0):printf("%u\n",y);}

kiểm tra và kết quả

int main()
{g(18,27,0);
 g(50,20,0);
 g(447,501,0);
 g(9894,2628,0);
}

18=(27*0)+18
27=(18*1)+9
18=(9*2)+0
9
50=(20*2)+10
20=(10*2)+0
10
447=(501*0)+447
501=(447*1)+54
447=(54*8)+15
54=(15*3)+9
15=(9*1)+6
9=(6*1)+3
6=(3*2)+0
3
9894=(2628*3)+2010
2628=(2010*1)+618
2010=(618*3)+156
618=(156*3)+150
156=(150*1)+6
150=(6*25)+0
6

0

Java 133

public void z(int i,int j){for(int d=1;d!=0;i=j,j=d){d=i%j;System.out.println(i+"=("+j+"*"+((i-d)/j)+")+"+d);}System.out.println(i);}

Nó không làm thuật toán Euclide thông thường. Thay vào đó, nó sử dụng mô-đun và sau đó tính số thứ 2 để nhân với khi nó được in ra. Bạn cũng có thể làm cho nó ngắn hơn bằng cách biến nó thành biểu thức lambda, nhưng tôi không biết làm thế nào.

public void z(int i, int j)
{
    for(int d=1;d!=0;i=j,j=d)
    {
        d=i%j;
        System.out.println(i+"=("+j+"*"+((i-d)/j)+")+"+d);
    }
    System.out.println(i);
}

Tôi biết đã hơn 1,5 năm, nhưng bạn có thể xóa public , thay đổi thứ hai printlnthành printvà thay đổi d!=0thành d>0. Ngoài ra, hiện tại nó cung cấp một đầu ra không chính xác cho các hàng đầu tiên. Điều này có thể được sửa chữa bằng cách thêm if(d!=i)vào trước System.out.println(i+"=("+j+"*"+((i-d)/j)+")+"+d);. Vì vậy, trong tổng số: void z(int i,int j){for(int d=1;d>0;i=j,j=d){d=i%j;if(d!=i)System.out.println(i+"=("+j+"*"+((i-d)/j)+")+"+d);}System.out.print(i);}( 131 byte và đã sửa lỗi)
Kevin Cruijssen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.