Евклідовий алгоритм (для пошуку найбільшого спільного дільника)


22

Змагання

Написати програму або функцію, яка приймає два вхідні цілі числа, iі jта виводить їх найбільший спільний дільник; розраховується за допомогою алгоритму Евкліда (див. нижче).


Вхідні дані

Введення може сприйматися як розділене пробілом рядкове подання iта jабо як два окремих числа. Можна припустити, що цілі числа будуть меншими або рівними 10 000. Можна також припустити, що цілі числа введення не будуть простими один одному.


Евклідова розбивка

Чим більше число між ними, iі jділиться на менші, наскільки це можливо. Потім додається залишок. Цей процес повторюється з залишком і попереднім номером, поки не стане залишок 0.

Наприклад, якщо введення було 1599 650:

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

Кінцеве число 13,, є найбільшим спільним дільником двох цілих чисел. Його можна візуалізувати так:


Вихідні дані

Вашим результатом має бути розбивка у наведеній вище формі, а потім новий рядок та GCD. Він може виводитися через будь-який носій.


Приклади

Вхідні дані

18 27
50 20
447 501
9894 2628

Виходи

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

Примітка. Виходи не повинні розташовуватись так, як вони були вище. Інтервал призначений лише для наочності. Потрібні дужки.


Бонус

Якщо ваш вихід буде розміщений як вище, ви можете додати бонус -10% до своєї оцінки.


1. Чи можна вважати, що найбільше число задається першим? 2. Під бонусом ви маєте на увазі, що ширина поля повинна бути постійною і достатньою, щоб забезпечити один пробіл перед найбільшою кількістю? (із пробілами, що йдуть раніше лівою дужкою у другому стовпчику чисел.) Ви повинні уникати неоднозначних фраз, таких як "як вони вгорі", коли вихід є змінним. Гаразд, якщо потрібний вихід фіксований.
Рівень Рівер Сент

Добре, я бачу, що деякі приклади мають найбільшу кількість секунд
рівень річки Св.

З початковою назвою було добре, я прокоментував те, що сталося на meta.codegolf.stackexchange.com/q/7043/15599 . Словосполучення «найбільший загальний знаменник» було помилковим. "Знаменник" відноситься до дробів. Гуглінг "найбільший спільний знаменник" дає результати лише для "найбільшого спільного дільника / фактора".
Рівень Рівер Сент

Я подумав, що з назвою все гаразд, але я змінив його на "The", щоб нікого не викликати удоволення. Дякуємо за редагування у "дільнику", BTW. @steveverrill
Zach Gates

Відповіді:


4

Pyth, 33 байти

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

Спробуйте в Інтернеті: Демонстрація або Тестовий набір

Пояснення:

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 байт

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

Спробуйте його в Інтернеті в інтерпретаторі CJam .

Як це працює

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

Пітон 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`

Рекурсивна функція, яка повертає багаторядковий рядок. Функція створює перший рядок, потім додає його до рекурсивного результату з наступною парою чисел в алгоритмі Евкліда. Після того, як друге число дорівнює нулю, ми беремо рядок іншого числа за базовий регістр, внаслідок чого він буде надрукований у власному рядку в кінці.

Форматування здійснюється за допомогою підстановки рядків, використовуючи ціле ділення для отримання мультиплікації.

Одному гика потрібно починати з того, що більша кількість приймається за меншу кількість. Зручно, якщо числа в неправильному порядку, перший крок алгоритму Евкліда перевертає їх. Щоб цей крок не відображався, додайте поточний рядок лише тоді, коли перше число є принаймні другим (рівність потрібна, скажімо 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

Сортування введення за розміром займає багато байт: /
зводиться до цього:

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

Вихідні дані

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

Для задоволення від цього я зробив і правильно розташовану версію, давши мені оцінку 233 * 0,9 == 209,7 байт.

Оновлення Я зміг скоротити це з 285 байтів, і тепер він працює для довільно довгих чисел, якщо викликає gawk4 з -Mопцією.

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

Але я все-таки відчув, що я десь наткнувся на якийсь ментальний блок ...

Вихід (gawk4 викликається за допомогою awk -M -f code.awk)

6837125332653632513763 18237983363879361 (вхід)
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

Додано деякі нові рядки та вкладки

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

Я можу зберегти довжини початкових значень для x, y та x% y на початку, тому що вони можуть лише скоротити кожен крок. Але для коефіцієнта я маю визначити максимальну довжину перед тим, як щось надрукувати, оскільки його довжина може змінюватися. Я використовую $iтут масив, тому що він зберігає два символи в порівнянні з використанням [i] кожного разу.


4

C ++, компілятор GCC, 171 байт (-10%, тому 154 байти)

добре, так що моя перша спроба ..

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

поради щодо кодування гольфу.

PS Чи потрібно підраховувати байти стандартних файлів заголовка та int main під час використання c ++? Якщо виключити, це зменшує 50 байт


Примітка. Я виключив пробіл, який використовується для красивого коду.
Деванг Джаячандран

3

T-SQL (2012+), 268 байт

Реалізується як функція вбудованої таблиці, яка виконує рекурсивний CTE. Можливо, варто спробувати ввести формат для 10% бонусу, але це доведеться почекати.

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

Пояснення та використання:

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

Обр. 1: Рубін, 86

Рекурсивний алгоритм, завдяки підказці від 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)}

Випуск 0: Рубін, 93

Це насправді взагалі не спрацювало добре. whileЦикл займає надто багато символів, особливо з end. Я не бачу способів уникнути цього. Рекурсія потребує іменованої функції замість лямбда, яка також з'їсть багато символів.

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

Назвіть це так:

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)

Ви можете використовувати рекурсію через a=->i,j{...} та дзвінки aчерез a[1,2]- не впевнені, що це врятує вас символів.
Дверна ручка

@Doorknob спасибі за підказку, я не знав про той синтаксис виклику функцій лямбда (див. Моє використання f.call.) Насправді це трохи коротше, але все ж далеко від Python.
Рівень Рівер Сент

2

PowerShell, 84

Рекурсивний блок коду, що зберігається у змінній. Викликайте це & $e num1 num2, наприклад:

$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

У більш читаному вигляді вона робить наступне (для більш чіткого коду, я поставив повні імена команд, більше пробілів у рядку та зробив явні команди конвеєра виведення явними):

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

Одне роздратування з точки зору кодегольфа; PoSh не має цілого поділу, 10/3 повертає подвійне, але приводить результат до цілого числа, і воно не завжди округляється , він округляє N.5 до найближчого парного числа - вгору або вниз. Отже [int](99/2) == 50.

Це залишає два незручні варіанти:

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

# or, worse

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

Ось чому я повинен записати деяких персонажів, роблячи:

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

Крім того, це кількість

і відсутність потрійного оператора, який дійсно шкодить.

У мене також є ітеративна версія, яка, досить непогано, також має 84 символи:

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

Повністю анонімний кодблок, тому запустіть його

& {*codeblock*} 1599 650

2

PHP, 118 байт

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

Спробуйте в Інтернеті!

PHP, 131 байт

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

Спробуйте в Інтернеті!

-4 Байти замінити list(,$n,$m)=$argvна [,$n,$m]=$argvпотреби PHP> = 7.1



2

JavaScript (ES6), 74 50 62 61 55 байт

f=(x,y)=>y?y>x?y:x+`=(${y}*${x/y|0})+${x%=y}
`+f(y,x):x
  • Жертвує 12 байт, що дозволяє передавати цілі числа в будь-якому порядку, а не найбільші спочатку.

Спробуй це

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>


Пояснення

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 байти

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

тест та результати

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

Це не робить звичайний евклідовий алгоритм. Натомість він використовує модуль, а потім обчислює 2-е число, щоб помножити на його друк. Ви також можете зробити це коротше, перетворивши його на лямбда-вираз, але я не знаю як.

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

Я знаю, що минуло більше 1,5 років, але ви можете видалити public , змінити другий printlnна printі змінити d!=0на d>0. Крім того, він наразі дає неправильний вихід для перших рядків. Це можна виправити, додавши if(d!=i)перед System.out.println(i+"=("+j+"*"+((i-d)/j)+")+"+d);. Отже, загалом: 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 байт і виправлено помилку)
Кевін Кройсейсен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.