Öklid Algoritması (en büyük ortak böleni bulmak için)


22

Meydan okuma

Bir program ya da iki giriş tamsayı alsın, fonksiyonunu yazın ive jve onların büyük ortak böleni verir; Öklid algoritması kullanılarak hesaplanmıştır (aşağıya bakınız).


Giriş

Girdi, alanla ayrılmış bir dize temsili ive jveya iki ayrı tamsayı olarak alınabilir. Tam sayıların 10.000’den küçük veya ona eşit olacağını varsayabilirsiniz. Ayrıca, giriş tam sayılarının birbirine asıl olmayacağını da varsayabilirsiniz.


Öklid Dağılımı

Aradaki ive arasındaki büyük sayı j, mümkün olduğu kadar küçük sayılara bölünür. Ardından, kalan eklenir. Bu işlem geri kalan ve önceki sayı ile, geri kalana kadar tekrarlanır 0.

Örneğin, eğer giriş 1599 650:

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

Son sayı,, 13iki girdi tamsayısının en büyük ortak bölenidir. Bu şekilde görselleştirilebilir:


Çıktı

Çıktınız yukarıdaki formdaki arıza olmalı, ardından yeni bir satır ve GCD. Herhangi bir ortamdan çıktı alınabilir.


Örnekler

Girdiler

18 27
50 20
447 501
9894 2628

çıktılar

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

Not: Çıktıların yukarıda oldukları gibi boşluk bırakılması gerekmez. Boşluk sadece netlik içindir. Parantez gereklidir.


Bonus

Çıktınız yukarıdaki gibi aralıklıysa, puanınıza% -10 bonus ekleyebilirsiniz.


1. En büyük sayının ilk verildiğini varsayabilir miyiz? 2. Bonus için, alan genişliğinin sabit olması ve en büyük sayıdan önce bir alana izin vermek için yeterli olması gerektiği anlamına mı geliyorsunuz? ( Sayıların ikinci sütunda sol parantezden önce boşluklar gelecek .) Çıktı değişken olduğunda, "yukarıdaki gibi" gibi belirsiz ifadelerden kaçınmalısınız. İstenilen çıktı sabitse tamamdır.
Seviye River St

Tamam, bazı örneklerin ikinci en büyük sayıya sahip olduğunu görüyorum
Level River St

Orijinal başlığın yolunda gitti, meta.codegolf.stackexchange.com/q/7043/15599 adresinde neler olduğu hakkında yorum yaptım . Ancak "en büyük ortak payda" ifadesi yanlıştı. "Payda" kesirlerle ilgilidir. Googling "en büyük ortak payda" sadece "en büyük ortak bölen / faktör" için sonuç verir.
Seviye Nehri St

Başlığın uygun olduğunu düşündüm ama kimseyi memnun etmemek için "The" olarak değiştirdim. BTW "bölen" de düzenlediğiniz için teşekkür ederiz. @steveverrill
Zach Gates,

Yanıtlar:


4

Pyth, 33 bayt

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

Çevrimiçi deneyin: Gösteri veya Test Paketi

Açıklama:

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 bayt

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

CJam tercümanında çevrimiçi olarak deneyin .

Nasıl çalışır

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

Python 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`

Çok satırlı bir dize döndüren özyinelemeli bir işlev. İşlev ilk satırı oluşturur, sonra Euclid algoritmasında sonraki sayı çiftleriyle özyinelemeli sonuçlara ekler. İkinci sayı sıfır olduğunda, diğer sayının dizgesini temel durum olarak alırız ve sonunda kendi satırına yazdırılmasını sağlar.

Biçimlendirme, çarpımı elde etmek için tamsayı bölme kullanılarak dize değiştirme yoluyla yapılır.

Bir hıçkırık, daha küçük sayılardan daha büyük sayılar alınarak başlamalıdır. Elverişli olarak, sayılar yanlış sırada ise, Euclidian algoritmasının ilk adımı bunları çevirir. Bu adımın görünmesini engellemek için, geçerli satırı yalnızca ilk sayı en az ikinci ise ekleyin (eşitlik gerekir f(9,9)).


5

awk, 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

Girdiyi boyuta göre sıralamak çok fazla bayt alır
:

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

Çıktı

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

Sadece eğlenmek için ben de düzgün aralıklı bir sürüm yaptım, bana 233 * 0.9 == 209.7 bayt puanı verdi.

Güncelleme Bunu 285 bayttan kısaltmayı başardım ve şimdi -Mseçenekle gawk4'ü çağırıyorsanız keyfi olarak uzun sayılar için çalışıyor .

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

Ama hala orada bir yerlerde bir zihinsel engelle karşılaştığımı hissediyorum.

Çıkış (gawk4 ile çağrılır awk -M -f code.awk)

6837125332653632513763 18237983363879361 (giriş)
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) + 948032500137
        15613369418631 = (948032500137 * 16) + 444849416439
          948032500137 = (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 = (1135914x3) + 637293
               1135914 = (637293 * 1) + 498621
                637293 = (498621 * 1) + 138672
                498621 = (138672 x 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

Bazı yeni satırlar ve sekmeler eklendi

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

Başlangıç ​​değerlerinin uzunluklarını başlangıçta x, y ve x% y için kaydedebilirim, çünkü her adımda yalnızca kısaltabilirler. Ancak faktöre göre, herhangi bir şeyi yazdırmadan önce maksimum uzunluğu belirlemeliyim çünkü uzunluğu değişebilir. $iBurada dizi olarak kullanıyorum , çünkü her seferinde [i] kullanmaya kıyasla iki karakter kaydeder.


4

C ++, GCC derleyicisi, 171 bayt (% -10, yani 154 bayt)

tamam öyleyse benim ilk denemem ..

#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;
}

golf kodları için ipuçları takdir etti.

PS c ++ kullanırken standart başlık dosyalarının bayt sayımı ve int main gerekli midir? Bunun dışında 50 bayt azaltır


Not: Kodu güzel yapmak için kullanılan beyaz alanı hariç tuttum.
Devang Jayachandran 27:15

3

T-SQL (2012+), 268 bayt

Özyinelemeli bir CTE yürüten bir satır içi tablo işlevi olarak uygulanır. % 10 bonus için biçimlendirme koymaya çalışırken değerli olabilir, ancak bu beklemek zorunda kalacak.

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

Açıklama ve kullanım:

--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: Yakut, 86

Özyinelemeli algoritma, Doorknob'dan bahşiş sayesinde.

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: Yakut, 93

Bu gerçekten hiç işe yaramadı. whileDöngü özellikle birlikte, çok fazla karakter kaplıyor end. Bundan kaçınmanın bir yolunu göremiyorum. Özyineleme, çok fazla karakter tüketen bir lambda yerine adlandırılmış bir fonksiyon gerektirecektir.

->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}

Buna şöyle diyoruz:

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)

Sen aracılığıyla Özyinelemeyi kullanabilirsiniz a=->i,j{...}ve çağrı ayoluyla a[1,2]bu size karakterleri kaydetmek olsaydı bile, -not olun.
Doorknob

@Doorknob bahşiş için teşekkürler, lambda işlevlerini çağırmak için sözdiziminden haberdar değildim (kullanımımı görün f.call.) Aslında Python'dan biraz daha kısa, ama yine de çok uzun bir yol.
Seviye Nehri St

2

PowerShell, 84

Bir değişkende saklanan özyinelemeli bir kod bloğu. Şunu davet edin & $e num1 num2, örneğin:

$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

Daha okunabilir bir formda, aşağıdakileri yapar (daha net kod için nb. Komut adlarının tamamını, dizgede daha fazla boşluk bıraktım ve boru hattı çıktı komutlarını açık hale getirdim):

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
    }
}

Kodlayıcı bakış açısından bir sıkıntı; PoSh tamsayı bölme işlemine sahip değil, 10/3 bir Double döndürüyor, ancak sonucu bir tamsayıya çeviriyor ve her zaman aşağı yuvarlamıyor, N.5'i en yakın çift sayıya veya aşağıya yuvarlıyor . Yani [int](99/2) == 50.

Bu iki garip seçenek bırakıyor:

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

# or, worse

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

Bu yüzden bazı karakterleri yakmam gerekiyor:

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

Bunun dışında, bu sayı

ve gerçekten acı veren üçlü operatör eksikliği.

Ayrıca 84 karakterden oluşan yinelemeli bir versiyonum da var:

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

Tamamen anonim kod bloğu, bu nedenle çalıştır

& {*codeblock*} 1599 650

2

PHP, 118 Bayt

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)."
":"";

Çevrimiçi deneyin!

PHP, 131 Bayt

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)."
":"";

Çevrimiçi deneyin!

-4 Bayt list(,$n,$m)=$argv, [,$n,$m]=$argvgereksinimler yerine PHP> = 7.1



2

JavaScript (ES6), 74 50 62 61 55 bayt

f=(x,y)=>y?y>x?y:x+`=(${y}*${x/y|0})+${x%=y}
`+f(y,x):x
  • Tamsayıların en büyüğü yerine herhangi bir sıraya göre geçirilmesine izin veren 12 bayt feda edildi.

Dene

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>


açıklama

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

JS, 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 bayt

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);}

test ve sonuçlar

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);}

Düzenli Öklid algoritması yapmaz. Bunun yerine, modülü kullanır ve ardından yazdırıldığında çarpılacak 2. sayıyı hesaplar. Bunu bir lambda ifadesine dönüştürerek de kısaltabilirsiniz, ancak nasıl olduğundan emin değilim.

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);
}

Ben 1.5 yıldan fazla oldu biliyorum ama kaldırabilir public , ikinci değiştirmek printlniçin print, ve değişimi d!=0için d>0. Ayrıca, şu anda ilk satırlar için yanlış çıktı veriyor. Bu if(d!=i)önüne ekleyerek düzeltilebilir System.out.println(i+"=("+j+"*"+((i-d)/j)+")+"+d);. Toplamda: 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 bayt & bug-sabit)
Kevin Cruijssen
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.