欧几里得算法(用于找到最大公约数)


22

挑战

编写一个程序或函数,它接受两个输入整数ij,并输出它们的最大公约数;通过使用欧几里得算法计算得出(见下文)。


输入项

输入可以作为和的空格分隔的字符串表示形式ij或作为两个单独的整数。您可以假设整数将小于或等于10,000。您还可以假定输入整数不会互为素数。


欧几里得分解

之间的较大数量ij由较小的分割多次可能的。然后,添加其余部分。对剩余数和前一个数字重复此过程,直到剩余数变为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.对于奖金,您的意思是字段宽度应该是恒定的,并且正好足以在最大数字之前留出一个空格?(数字第二列中左括号的空格。)当输出可变时,应避免使用不明确的措词,例如“因为它们在上方”。如果所需的输出固定,就可以。
级圣河

好吧,我看到一些例子的数量最多,仅次于
Level River St

您的原始标题还不错,我已经评论了meta.codegolf.stackexchange.com/q/7043/15599所发生的事情。但是,“最大公分母”这一说法是错误的。“分母”涉及分数。谷歌搜索“最大公分母”仅给出“最大公除数/因数”的结果。
级圣河

我以为标题可以,但是为了不让任何人不满意,我将其更改为“ The”。感谢您在BTW的“除数”中进行编辑。@steveverrill
Zach Gates

Answers:


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

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`

一个返回多行字符串的递归函数。该函数创建第一行,然后将其添加到递归结果中,并带有欧几里得算法中的下一对数字。一旦第二个数字为零,我们就将另一个数字的字符串作为基本情况,使它最后打印在自己的行上。

格式化是通过字符串替换完成的,使用整数除法获得被乘数。

一个打ic需要从较大的数字开始到较小的数字开始。方便地,如果数字顺序错误,则Euclidian算法的第一步将其翻转。为防止显示此步骤,仅在第一个数字至少是第二个数字时才添加当前行(例如,需要等号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个字节缩短,现在,如果使用该-M选项调用gawk4,它可以处理任意长的数字。

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在这里用作数组,因为与每次使用a [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使用c ++时是否需要计算标准头文件和int main的字节数?排除它会减少50个字节


注意:我排除了使代码漂亮的空白。
Devang Jayachandran 2015年

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:Ruby,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)}

Rev 0:Ruby,93岁

确实根本无法解决问题。该while循环占用了太多的字符,尤其是与end。我看不到一种避免的方法。递归将需要一个命名函数而不是lambda,这也会占用很多字符。

->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感谢您的提示,我不知道用于调用lambda函数的语法(请参阅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

以一种更具可读性的形式,它执行以下操作(为了更清晰的代码,我将完整的Commandlet名称放在字符串中,并在字符串中放置更多空格,并使管道输出命令变得明确):

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返回Double,但是将结果强制转换为整数,并且并不总是向下取整,它会将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

Japt43 42 41字节

我新发现的Japt“技能”似乎越来越差,而不是更好!

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

在线尝试


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

它不执行常规的欧几里得算法。相反,它使用模数,然后计算第二个数字乘以它的打印时间。您也可以通过将其转换为lambda表达式来使其更短,但我不确定如何做到。

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 ,将第二个更改printlnprint,然后更改d!=0d>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个字节及错误修正)
凯文Cruijssen
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.