L'algoritmo euclideo (per trovare il massimo comun divisore)


22

La sfida

Scrivere un programma o funzione che prende due interi ingresso, ie j, e fornisce in uscita il loro massimo comun divisore; calcolato usando l' algoritmo euclideo (vedi sotto).


Ingresso

Ingresso può essere preso come una rappresentazione di stringa delimitato da spazi di ie jo come due numeri interi separati. Puoi presumere che i numeri interi saranno inferiori o uguali a 10.000. Puoi anche supporre che gli interi di input non siano primi l'uno con l'altro.


Ripartizione euclidea

Il numero più grande tra ie jè diviso per il più piccolo il maggior numero di volte possibile. Quindi, viene aggiunto il resto. Questo processo si ripete con il resto e il numero precedente, fino a quando il resto diventa 0.

Ad esempio, se l'input era 1599 650:

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

Il numero finale 13, è il massimo comune divisore dei due numeri interi di input. Può essere visualizzato in questo modo:


Produzione

L'output deve essere la suddivisione nel modulo sopra, seguito da una nuova riga e dal GCD. Può essere emesso attraverso qualsiasi supporto.


Esempi

ingressi

18 27
50 20
447 501
9894 2628

Uscite

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

Nota: le uscite non devono essere distanziate come sopra. La spaziatura è solo per chiarezza. Sono necessarie le parentesi.


indennità

Se l'output è spaziato come sopra, puoi aggiungere un bonus del -10% al tuo punteggio.


1. Possiamo presumere che venga dato per primo il numero più grande? 2. Per il bonus, intendi che la larghezza del campo dovrebbe essere costante e quanto basta per consentire uno spazio prima del numero più grande? (con gli spazi che precedono la parentesi sinistra nella seconda colonna di numeri). Dovresti evitare frasi ambigue come "come sono sopra" quando l'output è variabile. Va bene se l'output richiesto è fisso.
Level River St

Ok, vedo che alcuni esempi hanno il numero maggiore secondo
Level River St

Il tuo titolo originale era OK, ho commentato cosa è successo su meta.codegolf.stackexchange.com/q/7043/15599 . La frase "massimo comune denominatore" era tuttavia sbagliata. "Denominatore" si riferisce alle frazioni. Googling "massimo comune denominatore" fornisce risultati solo per "massimo comune divisore / fattore".
Level River St

Ho pensato che il titolo fosse OK, ma l'ho cambiato in "The" per non dispiacere a nessuno. Grazie per il montaggio in "divisore", BTW. @steveverrill
Zach Gates,

Risposte:


4

Pyth, 33 byte

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

Provalo online: dimostrazione o suite di test

Spiegazione:

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

Provalo online nell'interprete CJam .

Come funziona

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`

Una funzione ricorsiva che restituisce una stringa multilinea. La funzione crea la prima riga, quindi la aggiunge al risultato ricorsivo con la successiva coppia di numeri nell'algoritmo euclideo. Una volta che il secondo numero è zero, prendiamo la stringa dell'altro numero come caso base, facendolo stampare alla sua stessa riga alla fine.

La formattazione avviene tramite sostituzione di stringa, usando la divisione di interi per ottenere il multiplicando.

È necessario un singhiozzo per iniziare con il numero più grande preso con il numero più piccolo. Convenientemente, se i numeri sono nell'ordine sbagliato, il primo passo dell'algoritmo euclideo li inverte. Per evitare che questo passaggio venga visualizzato, aggiungi la riga corrente solo se il primo numero è almeno il secondo (l'uguaglianza è necessaria, diciamo 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

L'ordinamento dell'input per dimensione richiede molti byte: /
Si riduce a questo:

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

Produzione

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

Solo per il gusto di farlo, ho realizzato anche una versione ben spaziata, dandomi un punteggio di 233 * 0,9 == 209,7 byte.

Aggiornamento Sono stato in grado di accorciare questo da 285 byte e ora funziona con numeri arbitrariamente lunghi se si chiama gawk4 con l' -Mopzione.

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

Ma ho ancora la sensazione che mi sono imbattuto in qualche blocco mentale lì da qualche parte ...

Output (gawk4 chiamato con awk -M -f code.awk)

6837125332653632513763 18237983363879361 (input)
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 = (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

Alcune nuove righe e schede aggiunte

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

Posso salvare le lunghezze dei valori iniziali per x, ye x% y all'inizio, perché possono solo accorciare ogni passaggio. Ma per il fattore devo determinare la lunghezza massima prima di stampare qualsiasi cosa, perché la sua lunghezza può variare. Uso $icome un array qui, perché salva due caratteri rispetto all'uso di una [i] ogni volta.


4

C ++, compilatore GCC, 171 byte (-10%, quindi 154 byte)

okay quindi il mio primo tentativo ..

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

suggerimenti per il codice golf apprezzato.

PS È necessario contare i byte di file di intestazione standard e int main durante l'utilizzo di c ++? Escludendolo si riducono i 50 byte


Nota: ho escluso lo spazio bianco utilizzato per rendere grazioso il codice.
Devang Jayachandran,

3

T-SQL (2012+), 268 byte

Implementato come una funzione di tabella inline che esegue un CTE ricorsivo. Potrebbe valere la pena provare a inserire la formattazione per il bonus del 10%, ma dovrà aspettare.

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

Spiegazione e utilizzo:

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

Algoritmo ricorsivo, grazie al suggerimento di 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)}

Verso 0: Ruby, 93

Questo non ha funzionato affatto bene. Il whileloop occupa troppi personaggi, specialmente con end. Non riesco a vedere un modo per evitarlo. La ricorsione richiederebbe una funzione con nome invece di una lambda, che consumerebbe anche molti personaggi.

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

Chiamalo così:

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)

Puoi usare la ricorsione via a=->i,j{...}e chiamare avia a[1,2]- non sono sicuro se questo ti salverebbe i personaggi.
Maniglia della porta

@Doorknob grazie per il suggerimento, non ero a conoscenza di quella sintassi per aver chiamato le funzioni lambda (vedi il mio uso di f.call.) In realtà è un po 'più breve, ma ancora molto lontano da Python.
Level River St

2

PowerShell, 84

Un blocco di codice ricorsivo, memorizzato in una variabile. Invocalo con & $e num1 num2, ad esempio:

$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

In una forma più leggibile, esegue le seguenti operazioni (nb. Per un codice più chiaro, ho inserito i nomi completi dei comandi, più spazi nella stringa e reso espliciti i comandi di output della pipeline):

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

Un fastidio dal punto di vista di codegolf; PoSh non ha divisione in numeri interi, 10/3 restituisce un doppio, ma lancia il risultato in un numero intero e non sempre arrotonda per difetto , arrotonda N.5 al numero pari più vicino - su o giù. Così [int](99/2) == 50.

Ciò lascia due scelte imbarazzanti:

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

# or, worse

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

Ecco perché devo bruciare alcuni personaggi facendo:

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

A parte questo, è il numero di

e la mancanza di un operatore ternario che fa davvero male.

Ho anche una versione iterativa che, piuttosto bene, ha anche 84 caratteri:

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

Blocco del codice completamente anonimo, quindi eseguilo con

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

Provalo online!

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

Provalo online!

-4 byte sostituiscono list(,$n,$m)=$argvcon [,$n,$m]=$argvesigenze PHP> = 7.1


2

Japt , 43 42 41 byte

Le mie nuove "abilità" Japt sembrano peggiorare, non meglio!

?U>V?ßVU :[V'='(U'*V/U|0')'+V%=UR,ßVU]¬:V

Provalo online


2

JavaScript (ES6), 74 50 62 61 55 55 byte

f=(x,y)=>y?y>x?y:x+`=(${y}*${x/y|0})+${x%=y}
`+f(y,x):x
  • Sacrificato 12 byte che consente il passaggio degli interi in qualsiasi ordine, piuttosto che il più grande per primo.

Provalo

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>


Spiegazione

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

test e risultati

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

Non fa il normale algoritmo euclideo. Invece, usa il modulo e quindi calcola il 2o numero per moltiplicarlo per quando viene stampato. Puoi anche accorciarlo trasformandolo in un'espressione lambda, ma non sono sicuro di come.

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

So che sono trascorsi oltre 1,5 anni, ma puoi rimuovere public , cambiare il secondo printlnin printe passare d!=0a d>0. Inoltre, attualmente fornisce un output errato per le prime righe. Questo può essere risolto aggiungendo if(d!=i)davanti a System.out.println(i+"=("+j+"*"+((i-d)/j)+")+"+d);. Quindi in totale: 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 e bug-fixed)
Kevin Cruijssen,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.