El algoritmo euclidiano (para encontrar el máximo divisor común)


22

El reto

Escribir un programa o función que toma dos números enteros de entrada, iy j, y da salida a su máximo común divisor; calculado utilizando el algoritmo euclidiano (ver más abajo).


Entrada

De entrada puede ser tomado como una representación de cadena delimitada por espacios de iy jo como dos enteros separados. Puede suponer que los enteros serán menores o iguales a 10,000. También puede suponer que los enteros de entrada no serán primos entre sí.


Desglose Euclidiano

El número mayor entre iy jse divide por el menor tantas veces como sea posible. Luego, se agrega el resto. Este proceso se repite con el resto y el número anterior, hasta que el resto se convierta 0.

Por ejemplo, si la entrada fue 1599 650:

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

El número final 13, es el máximo común divisor de los dos enteros de entrada. Se puede visualizar así:


Salida

Su salida debe ser el desglose en el formulario anterior, seguido de una nueva línea y el MCD. Se puede emitir a través de cualquier medio.


Ejemplos

Entradas

18 27
50 20
447 501
9894 2628

Salidas

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: Las salidas no tienen que estar espaciadas como están arriba. El espacio es solo para mayor claridad. Se requieren paréntesis.


Prima

Si su producción está espaciada como se indica arriba, puede agregar un bono de -10% a su puntaje.


1. ¿Podemos suponer que el número más grande se da primero? 2. Para la bonificación, ¿quiere decir que el ancho del campo debe ser constante y lo suficiente como para permitir un espacio antes del número más grande? (con los espacios antes del paréntesis izquierdo en la segunda columna de números). Debe evitar una frase ambigua como "como están arriba" cuando la salida es variable. Está bien si la salida requerida es fija.
Level River St

Ok, veo que algunos ejemplos tienen el segundo número más grande
Level River St

Su título original estaba bien, he comentado lo que sucedió en meta.codegolf.stackexchange.com/q/7043/15599 . Sin embargo, la frase "máximo común denominador" estaba mal. "Denominador" se refiere a fracciones. Buscar en Google el "máximo común denominador" solo da resultados para el "máximo común divisor / factor".
Level River St

Pensé que el título estaba bien, pero lo cambié a "The" para no desagradar a nadie. Gracias por editar en "divisor", por cierto. @steveverrill
Zach Gates

Respuestas:


4

Pyth, 33 bytes

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

Pruébelo en línea: Demostración o conjunto de pruebas

Explicación:

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 bytes

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

Pruébelo en línea en el intérprete de CJam .

Cómo funciona

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

Pitó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`

Una función recursiva que devuelve una cadena multilínea. La función crea la primera línea, luego la agrega al resultado recursivo con el siguiente par de números en el algoritmo euclidiano. Una vez que el segundo número es cero, tomamos la cadena del otro número como el caso base, haciendo que se imprima en su propia línea al final.

El formateo se realiza mediante la sustitución de cadenas, utilizando la división de enteros para obtener el multiplicando.

Un problema es comenzar con el número más grande que se toma del número más pequeño. Convenientemente, si los números están en el orden incorrecto, el primer paso del algoritmo euclidiano los voltea. Para evitar que se muestre este paso, solo agregue la línea actual si el primer número es al menos el segundo (se necesita igualdad para, por ejemplo 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

Ordenar la entrada por tamaño requiere muchos bytes: /
Se reduce a esto:

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

Salida

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

Solo por diversión, también hice una versión correctamente espaciada, dándome una puntuación de 233 * 0.9 == 209.7 bytes.

Actualización Pude acortar esto de 285 bytes y ahora funciona para números arbitrariamente largos si llama a gawk4 con la -Mopció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

Pero aún tengo la sensación de que me encontré con algún bloqueo mental allí en alguna parte ...

Salida (gawk4 llamado con awk -M -f code.awk)

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

Se agregaron algunas líneas nuevas y pestañas

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

Al principio puedo guardar las longitudes de los valores iniciales para x, y y x% y, porque solo pueden acortarse cada paso. Pero por el factor que tengo que determinar la longitud máxima antes de imprimir cualquier cosa, porque su longitud puede variar. Lo uso $icomo una matriz aquí, porque guarda dos caracteres en comparación con el uso de [i] cada vez.


4

C ++, compilador GCC, 171 bytes (-10%, 154 bytes)

está bien así que mi primer intento ..

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

consejos para codificar golf apreciados.

PD ¿Es necesario contar bytes de archivos de encabezado estándar e int main mientras se usa c ++? Excluirlo reduce 50 bytes


Nota: excluí el espacio en blanco utilizado para hacer que el código sea bonito.
Devang Jayachandran

3

T-SQL (2012+), 268 bytes

Implementado como una función de tabla en línea que ejecuta un CTE recursivo. Puede valer la pena intentar dar formato al bono del 10%, pero eso tendrá que esperar.

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

Explicación y uso:

--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: Rubí, 86

Algoritmo recursivo, gracias al consejo de 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: Rubí, 93

Esto realmente no ha funcionado bien en absoluto. El whilebucle ocupa demasiados caracteres, especialmente con el end. No puedo ver una forma de evitarlo. La recursión requeriría una función con nombre en lugar de una lambda, que también consumiría muchos caracteres.

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

Llámalo así:

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)

Puede usar la recursividad vía a=->i,j{...}y llamar avía a[1,2], aunque no estoy seguro de si esto le salvaría a los caracteres.
Pomo de la puerta

@Doorknob gracias por el consejo, no estaba al tanto de esa sintaxis para llamar a funciones lambda (vea mi uso de f.call). En realidad, es bastante más corta, pero aún está muy lejos de Python.
Level River St

2

PowerShell, 84

Un bloque de código recursivo, almacenado en una variable. Invocarlo con & $e num1 num2, por ejemplo:

$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

En una forma más legible, hace lo siguiente (nota: para un código más claro, puse los nombres completos de los comandos, más espacios en la cadena e hice explícitos los comandos de salida de la tubería):

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

Una molestia desde el punto de vista del codegolf; PoSh no tiene división de enteros, 10/3 devuelve un Doble, pero arroja el resultado a un entero y no siempre se redondea hacia abajo, redondea N.5 al número par más cercano - hacia arriba o hacia abajo. Asi que[int](99/2) == 50 .

Eso deja dos opciones incómodas:

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

# or, worse

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

Es por eso que tengo que quemar algunos personajes haciendo:

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

Aparte de eso, es el número de

y la falta de operador ternario que realmente duele.

También tengo una versión iterativa que, bastante bien, también tiene 84 caracteres:

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

Codeblock completamente anónimo, así que ejecútelo con

& {*codeblock*} 1599 650

2

PHP, 118 bytes

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

Pruébalo en línea!

PHP, 131 bytes

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

Pruébalo en línea!

-4 Bytes reemplazar list(,$n,$m)=$argvcon [,$n,$m]=$argvnecesidades PHP> = 7.1



2

JavaScript (ES6), 74 50 62 61 55 bytes

f=(x,y)=>y?y>x?y:x+`=(${y}*${x/y|0})+${x%=y}
`+f(y,x):x
  • Sacrificó 12 bytes permitiendo que los enteros se pasen en cualquier orden, en lugar del primero más grande.

Intentalo

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>


Explicación

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 bytes

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

prueba y resultados

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

No hace el algoritmo euclidiano regular. En cambio, usa un módulo y luego calcula el segundo número para multiplicarlo cuando se imprime. También puede hacer esto más corto convirtiéndolo en una expresión lambda, pero no estoy seguro de cómo.

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

Sé que han pasado más de 1,5 años, pero se puede quitar el public , cambie el segundo printlna print, y el cambio d!=0a d>0. Además, actualmente está dando una salida incorrecta para las primeras filas. Esto se puede solucionar agregando if(d!=i)delante de System.out.println(i+"=("+j+"*"+((i-d)/j)+")+"+d);. En total: 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 bytes y corrección de errores)
Kevin Cruijssen
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.