Реализации алгоритмов/Алгоритм Евклида: различия между версиями

Материал из Викиучебника — открытых книг для открытого мира
Содержимое удалено Содержимое добавлено
Тщательное оформление программного кода, примечаний, языки расположены в алфавитном порядке, добавлена программа для ПМК
Строка 1: Строка 1:
Далее приводятся реализации [[w:алгоритм Евклида|алгоритма Евклида]] для вычисления НОД на различных [[w:язык программирования|языках программирования]].
Далее приводятся реализации [[w:алгоритм Евклида|алгоритма Евклида]] для вычисления НОД на различных [[w:язык программирования|языках программирования]].
== [[Scheme]] ==
==[[w:Бейсик|BASIC]]==
===QBASIC, QuickBasic, VisualBasic (до версий с поддержкой .NET)===
Алгоритм вычитанием
Деление с остатком, без рекурсии:

<source lang="basic">
('''define''' gcd ('''lambda''' (a b)
Function GCD (a As Integer, b As Integer) As Integer
('''if''' (> a b) ('''gcd''' (- a b) b)
Dim d As Integer
('''if''' (< a b) ('''gcd''' a (- b a))
a))))
Do While a <> 0 and b <> 0
If a >=b Then

a = a mod b
== [[Ruby]] ==
Else

b = b mod a
Функция в [[рекурсия|рекурсивном]] виде:
End If

Loop
<source lang="ruby">
def gcd(a, b)
GCD = a + b
End Function
return a if b.zero?
gcd(b, a % b)
end
</source>
</source>


==[[w:C (язык программирования)|C]]==
Функция в нерекурсивном виде:
Тип T определён как <code>typedef … T;</code>, вместо <code>…</code> следует подставить любой целочисленный тип (<code>int</code>, <code>unsigned</code>, <code>short</code> и т. д.)


Деление с остатком, без рекурсии:
<source lang="ruby">
<source lang="c">
def gcd(a, b)
a, b = b, a % b until b.zero?
T gcd (T a, T b) {
a
T c;
while (b) {
end
c = a % b;
a = b;
b = c;
}
return (a < 0) ? -a : a;
}
</source>
</source>


Более короткое решение:
Алгоритм вычитанием:
<source lang="c">

T gcd (T a, T b) {
<source lang="ruby">
while (b)
def gcd(a, b)
if a > b
b ^= a ^= b ^= a %= b;
a -= b
return a;
}
else
b -= a
end while a != b
a
end
</source>
</source>


Деление с остатком, рекурсия:
== [[PHP]] ==
<source lang="c">

T gcd (T a, T b) {
<source lang="php">
return (b == 0) ? a : gcd(b, a % b);
function nod($a, $b)
}
{
while ($a <> 0 && $b <> 0) {
if ($a > $b)
$a= $a % $b;
else
$b= $b % $a;
$nod= $a + $b;
}
return $nod;
}
echo nod(5,3);
</source>
</source>


Вычитание, без рекурсии:
== [[Python]] ==
<source lang="c">

T gcd (T a, T b) {
Функция в [[рекурсия|рекурсивном]] виде:
while (a != b) {

if (a > b)
<source lang="python">
a -= b;
def gcd(a, b):
return a if b == 0 else gcd(b, a % b)
else
b -= a;
}
return a;
}
</source>
</source>


==[[w:C_Sharp|C#]]==
Функция в нерекурсивном виде:
Деление с остатком, без рекурсии:

<source lang="python">
<source lang="csharp">
def gcd(a, b):
int GCD (int a, int b)
{
while b:
a, b = b, a % b
while (b != 0)
return a
b = a % (a = b);
return a;
}
</source>
</source>


== [[Perl]] ==
==[[w:Erlang|Erlang]]==
Деление с остатком, рекурсия:
Функция в [[рекурсия|рекурсивном]] виде:
<source lang="erlang">

gcd(A, 0) -> A;
<source lang="perl">
gcd(A, B) -> gcd(B, (A rem B)).
sub nod
{
return $_[0] != 0 ? nod ( ( $_[1] % $_[0] ), $_[0] ) : $_[1];
}
</source>
</source>


==[[w:F_Sharp|F#]]==
== Shell ==
Деление с остатком, рекурсия:

<source lang="fsharp">
Функция в [[рекурсия|рекурсивном]] виде:
let rec nod a b =

match b with
<source lang="bash">
|0 -> a

nod () {
|b -> nod b (a % b)
n=1 a=$1 b=$2
if [[ $a -ne 0 ]]
then
nod $(( $b % $a )) $a
let "n = $?"
else
let "n = $b"
fi
return $n
}

nod $1 $2
echo "NOD is $?"
</source>
</source>


== [[Си (язык программирования)|Си]] ==
==[[w:Forth (язык программирования)|Forth]] (диалект [[RetroForth]])==
Деление с остатком, рекурсия:

<source lang="c"> int gcd(int a, int b) {
<source lang="forth">
: GCD ( n1 n2 -- n ) tuck mod 0; GCD ;
int c;
while (b) {
c = a % b;
a = b;
b = c;
}
return fabs(a);
}</source>

Более короткое решение:
<source lang="c">
int gcd(int a, int b) {
while(b) b^=a^=b^=a%=b;
return a;
}</source>

Та же функция в рекурсивном виде:
<source lang="c">
int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}</source>

Немного короче:

<source lang="c"> int gcd(int a, int b) {
return b? gcd(b, a % b) : a;
}
</source>
</source>


==[[w:Haskell|Haskell]]==
Алгоритм вычитанием:
Деление с остатком, рекурсия:
<source lang="c">
int gcd(int a, int b) {
while ( a != b) {
if (a > b) a -= b;
else b -= a;
}
return a;
}</source>

== [[Forth (язык программирования)|Форт]] (диалект [[RetroForth]]) ==

Рекурсивный алгоритм

: НОД ( n1 n2 -- n ) tuck mod 0; НОД ;

== [[Haskell]] ==
<source lang="haskell">
<source lang="haskell">
gcd :: Integral a => a -> a -> a
gcd :: Integral a => a -> a -> a
Строка 166: Строка 105:
</source>
</source>


== [[F#]] ==
==[[w:Java|Java]]==
Деление с остатком, без рекурсии:
Рекурсивный алгоритм
<source lang="java">
public static <T> T gcd (T a, T b) {
while (b != 0) {
T c = a % b;
a = b;
b = c;
}
return a;
}
</source>


Также допустимы функции, аналогичные написанным выше на C, например так:
<source lang="fsharp">
<source lang="java">
let rec nod a b =
public static <T> gcd (T a, T b) {
match b with
|0 -> a
while (b != 0)
|b -> nod b (a%b)
b ^= a ^= b ^= a %= b;
return a;
}
</source>
</source>
''*короткая запись работает не корректно. Например при начальных значениях 34 и 9 уже на следующем шаге значения получаются 43 и 0...''


Деление с остатком, рекурсия:
<source lang="java">
public static <T> T gcd (T a, T b) {
return b == 0 ? a : gcd(b, a % b);
}
</source>


== [[Глагол (язык программирования)|Глагол]] ==
==[[w:Паскаль (язык программирования)|Pascal]]==
Тип T определён как <code>type T = …;</code>, вместо <code>…</code> следует подставить любой целочисленный тип (<code>Integer</code>, <code>Byte</code>, <code>LongInt</code> и т. д.)
ЗАДАЧА НОД(a, b: ЦЕЛ): ЦЕЛ;

УКАЗ
Деление с остатком, без рекурсии:
ПОКА (a # 0) И (b # 0) ВЫП
ЕСЛИ a >= b ТО
a := a ОСТАТОК b
ИНАЧЕ
b := b ОСТАТОК a
КОН
КОН;
ВОЗВРАТ a + b
КОН НОД;
== [[Паскаль (язык программирования)|Pascal]] ==
Обычный алгоритм:
<source lang="pascal">
<source lang="pascal">
function nod(a, b: longint): longint;
function GCD (a, b: T): T;
begin
begin
while a * b <> 0 do
while a * b <> 0 do
if a > b
if a > b then
then a:= a mod b
a := a mod b
else b:= b mod a;
else
b := b mod a;
nod:= a + b;
gcd := a + b
end
end;
</source>
</source>


Более быстрый алгоритм:
Более быстрый алгоритм:
<source lang="pascal">
<source lang="pascal">
function nod (a, b: LongInt): LongInt;
function GCD (a, b: T): T;
var c: T;
var
begin
t: LongInt;
while b > 0 do
begin
while b > 0 do
begin
c := a mod b;
begin
t := a mod b;
a := b;
a := b;
b := c
b := t;
end;
end;
gcd := a
end;
nod := a;
end;

</source>
</source>


Деление с остатком, рекурсия:
В рекурсивном виде:
<source lang="pascal">
<source lang="pascal">
function nod(a, b: LongInt): LongInt;
function gcd (a, b: T): T;
begin
begin
if b = 0 then
if b = 0 then
nod := a
gcd := a
else
else
nod := nod (b, a mod b)
gcd := gcd(b, a mod b)
end
end;
</source>
</source>


==[[w:Perl|Perl]]==
== [[Пролог (язык программирования)|Prolog]] ==
Деление с остатком, рекурсия:

<source lang="perl">
?GCD(a,b,x)
sub gcd {

return $_[0] != 0 ? gcd ( ( $_[1] % $_[0] ), $_[0] ) : $_[1];
GCD(0,b,b) <-
GCD(a,0,a) <-
GCD(a,b,x) <- a >= b, m is a mod b, GCD(m, b, x)
GCD(a,b,x) <- a < b, m is b mod a, GCD(a, m, x)

=== [[SWI-Prolog]] ===

gcd(0,B,B).
gcd(A,0,A).

gcd(A,B,X) :- A >= B, M is A mod B, gcd(M, B, X).
gcd(A,B,X) :- A < B, M is B mod A, gcd(A, M, X).

=== [[Erlang]] ===

gcd(A, 0) -> A;
gcd(A, B) -> gcd(B, (A rem B)).
== [[Java]] ==
<source lang="java">
public class GCD {
public static int gcd(int a,int b) {
while (b !=0) {
int tmp = a%b;
a = b;
b = tmp;
}
return a;
}
}
}
</source>
</source>


==[[w:PHP|PHP]]==
Немного короче:
Деление с остатком, без рекурсии:
<source lang="java">
<source lang="php">
public class GCD {
function gcd ($a, $b) {
public static int gcd(int a,int b) {
return b == 0 ? a : gcd(b, a % b);
while ($a <> 0 && $b <> 0) {
if ($a > $b)
$a = $a % $b;
else
$b = $b % $a;
$gcd = $a + $b;
}
}
return $gcd;
}
}
echo gcd(5, 3);
</source>
</source>


==[[w:Пролог (язык программирования)|Prolog]]==
Также допустимы функции, аналогичные написанным выше на C, например так:
Деление с остатком, рекурсия:
<source lang="java">
<source lang="prolog">
public class GCD {
?GCD(a,b,x)
public static int gcd(int a,int b) {
while(b!=0) b^=a^=b^=a%=b;
return a;
}
}
</source>
''*короткая запись работает не корректно. Например при начальных значениях 34 и 9 уже на следующем шаге значения получаются 43 и 0...''


GCD(0,b,b) <-
== [[C#]] ==
GCD(a,0,a) <-
GCD(a,b,x) <- a >= b, m is a mod b, GCD(m, b, x)
GCD(a,b,x) <- a < b, m is b mod a, GCD(a, m, x)
</code>


===[[w:SWI-Prolog]]===
<source lang="csharp">
Деление с остатком, рекурсия:
int gcd(int a, int b)
<source>
{
gcd(0,B,B).
while (b != 0)
gcd(A,0,A).
b = a % (a = b);

return a;
gcd(A,B,X) :- A >= B, M is A mod B, gcd(M, B, X).
}
gcd(A,B,X) :- A < B, M is B mod A, gcd(A, M, X).
</source>
</source>


== [[MapBasic]] ==
==[[w:Python|Python]]==
Деление с остатком, без рекурсии:
<source lang="python">
def gcd (a, b):
while b:
a, b = b, a % b
return a
</source>


Деление с остатком, рекурсия:
<source lang="csharp">
<source lang="python">
Function NOD(a As Integer, b As Integer) As Integer
def gcd (a, b):
return a if b == 0 else gcd(b, a % b)
</source>


==[[:Ruby|Ruby]]==
Dim d As Integer
Деление с остатком, без рекурсии:
<source lang="ruby">
def gcd (a, b)
a, b = b, a % b until b.zero?
a
end
</source>


Деление с остатком, рекурсия:
Do While a <> 0 and b <> 0
<source lang="ruby">
def gcd (a, b)
return a if b.zero?
gcd(b, a % b)
end
</source>


Вычитание, без рекурсии:
If a >=b Then
<source lang="ruby">
a = a mod b
def gcd (a, b)
Else
b = b mod a
if a > b
a -= b
End If
else
b -= a
end while a != b
a
end
</source>


==[[w:Scheme|Scheme]]==
Loop
Вычитание, рекурсия:
('''define''' gcd ('''lambda''' (a b)
('''if''' (> a b) ('''gcd''' (- a b) b)
('''if''' (< a b) ('''gcd''' a (- b a))
a))))


==Shell==
d = a + b
Деление с остатком, рекурсия:
<source lang="bash">
gcd () {
n=1 a=$1 b=$2
if [[ $a -ne 0 ]]
then
gcd $(( $b % $a )) $a
let "n = $?"
else
let "n = $b"
fi
return $n
}


gcd $1 $2
End Function
echo "Greatest common divisor is $?"
</source>
</source>


==[[w:Глагол (язык программирования)|Глагол]]==
== Ассемблер ==
Деление с остатком, без рекурсии:
=== ARM ===
<source>
Алгоритм вычитанием
ЗАДАЧА НОД (a, b: ЦЕЛ): ЦЕЛ;
УКАЗ
ПОКА (a # 0) И (b # 0) ВЫП
ЕСЛИ a >= b ТО
a := a ОСТАТОК b
ИНАЧЕ
b := b ОСТАТОК a
КОН
КОН;
ВОЗВРАТ a + b
КОН НОД;
</source>

==Ассемблер==
===ARM===
Вычитание, без рекурсии:
<source lang="arm">
<source lang="arm">
loop CMP Ri, Rj ; проверка условий NE (i != j), GT (i > j) и LT (i < j);
loop CMP Ri, Rj ; проверка условий NE (i != j), GT (i > j) и LT (i < j);
Строка 328: Строка 318:
</source>
</source>


=== Z80 ===
===Z80===
Вычитание, без рекурсии:
Алгоритм вычитанием
<source lang="z80">
<source lang="z80">
GCD_DEHL: ;CALL Inputs: HL,DE; Output: DE
GCD_DEHL: ;CALL Inputs: HL,DE; Output: DE
Строка 342: Строка 332:
</source>
</source>


==Программируемые микрокалькуляторы «Электроника»==
== См. также ==
Деление с остатком, без рекурсии. Корректно обрабатываются любые целые числа (включая 0 и отрицательные). В вычислениях участвуют только регистры стека.

Использование: <первое число> В↑ <второе число> В/О С/П (НОД на индикаторе).
===МК-52 / 61 / 152 / 161===
<source>
00. Fx≠0 01. 13 02. ↔ 03. В↑ 04. FВx 05. ÷ 06. FВx 07. ↔ 08. K[x] 09. ×
10. − 11. Fx=0 12. 02 13. + 14. K|x| 15. С/П
</source>

==См. также==
* [[../Бинарный алгоритм вычисления НОД/]]
* [[../Бинарный алгоритм вычисления НОД/]]



Версия от 10:32, 25 апреля 2017

Далее приводятся реализации алгоритма Евклида для вычисления НОД на различных языках программирования.

BASIC

QBASIC, QuickBasic, VisualBasic (до версий с поддержкой .NET)

Деление с остатком, без рекурсии:

Function GCD (a As Integer, b As Integer) As Integer
	Dim d As Integer
	Do While a <> 0 and b <> 0
		If a >=b Then
			a = a mod b
		Else
			b = b mod a
		End If
	Loop
	GCD = a + b
End Function

C

Тип T определён как typedef … T;, вместо следует подставить любой целочисленный тип (int, unsigned, short и т. д.)

Деление с остатком, без рекурсии:

T gcd (T a, T b) {
    T c;
    while (b) {
        c = a % b;
        a = b;
        b = c;
    }
    return (a < 0) ? -a : a;
}

Более короткое решение:

T gcd (T a, T b) {
    while (b)
        b ^= a ^= b ^= a %= b;
    return a;
}

Деление с остатком, рекурсия:

T gcd (T a, T b) {
   return (b == 0) ? a : gcd(b, a % b);
}

Вычитание, без рекурсии:

T gcd (T a, T b) {
    while (a != b) {
        if (a > b)
            a -= b;
        else
            b -= a;
    }
    return a;
}

C#

Деление с остатком, без рекурсии:

int GCD (int a, int b)
{
    while (b != 0)
        b = a % (a = b);
    return a;
}

Erlang

Деление с остатком, рекурсия:

gcd(A, 0) -> A;
gcd(A, B) -> gcd(B, (A rem B)).

F#

Деление с остатком, рекурсия:

let rec nod a b =
    match b with
    |0 -> a
    |b -> nod b (a % b)

Forth (диалект RetroForth)

Деление с остатком, рекурсия:

: GCD ( n1 n2 -- n ) tuck mod 0; GCD ;

Haskell

Деление с остатком, рекурсия:

gcd :: Integral a => a -> a -> a
gcd 0 0 = error "НОД от 0 и 0 не определён."
gcd x y = gcd' (abs x) (abs y)
    where gcd' x 0 = x
          gcd' x y = gcd' y (x `rem` y)

Java

Деление с остатком, без рекурсии:

public static <T> T gcd (T a, T b) {
    while (b != 0) {
        T c = a % b;
        a = b;
        b = c;
    }
    return a;
}

Также допустимы функции, аналогичные написанным выше на C, например так:

public static <T> gcd (T a, T b) {
    while (b != 0)
        b ^= a ^= b ^= a %= b;
    return a;
}

*короткая запись работает не корректно. Например при начальных значениях 34 и 9 уже на следующем шаге значения получаются 43 и 0...

Деление с остатком, рекурсия:

public static <T> T gcd (T a, T b) {
    return b == 0 ? a : gcd(b, a % b);
}

Pascal

Тип T определён как type T = …;, вместо следует подставить любой целочисленный тип (Integer, Byte, LongInt и т. д.)

Деление с остатком, без рекурсии:

function GCD (a, b: T): T;
begin
    while a * b <> 0 do
       if a > b then
           a := a mod b
       else
           b := b mod a;
    gcd := a + b
end;

Более быстрый алгоритм:

function GCD (a, b: T): T;
var c: T;
begin
    while b > 0 do
    begin
        c := a mod b;
        a := b;
        b := c
    end;
    gcd := a
end;

Деление с остатком, рекурсия:

function gcd (a, b: T): T;
begin
   if b = 0 then
       gcd := a
   else
       gcd := gcd(b, a mod b)
end;

Perl

Деление с остатком, рекурсия:

sub gcd {
    return  $_[0] != 0  ?  gcd ( ( $_[1] % $_[0] ), $_[0] )  :  $_[1];
}

PHP

Деление с остатком, без рекурсии:

function gcd ($a, $b) {
    while ($a <> 0 && $b <> 0) {
        if ($a > $b)
            $a = $a % $b;
        else
            $b = $b % $a;
        $gcd = $a + $b;
    }
    return $gcd;
}
echo gcd(5, 3);

Prolog

Деление с остатком, рекурсия:

?GCD(a,b,x)

GCD(0,b,b) <-
GCD(a,0,a) <-
GCD(a,b,x) <- a >= b, m is a mod b, GCD(m, b, x)
GCD(a,b,x) <- a < b, m is b mod a, GCD(a, m, x)
</code>

===[[w:SWI-Prolog]]===
Деление с остатком, рекурсия:
<source>
gcd(0,B,B).
gcd(A,0,A).

gcd(A,B,X) :-  A >= B, M is A mod B, gcd(M, B, X).
gcd(A,B,X) :-  A < B, M is B mod A, gcd(A, M, X).

Python

Деление с остатком, без рекурсии:

def gcd (a, b):
    while b:
        a, b = b, a % b
    return a

Деление с остатком, рекурсия:

def gcd (a, b):
    return a if b == 0 else gcd(b, a % b)

Ruby

Деление с остатком, без рекурсии:

def gcd (a, b)
    a, b = b, a % b until b.zero?
    a
end

Деление с остатком, рекурсия:

def gcd (a, b)
    return a if b.zero?
    gcd(b, a % b)
end

Вычитание, без рекурсии:

def gcd (a, b)
    if a > b
        a -= b
    else
        b -= a
    end while a != b
    a
end

Scheme

Вычитание, рекурсия:

(define gcd (lambda (a b)
  (if (> a b) (gcd (- a b) b)
     (if (< a b) (gcd a (- b a))
        a))))

Shell

Деление с остатком, рекурсия:

gcd () {
   n=1 a=$1 b=$2
   if [[ $a -ne 0 ]]
   then
      gcd $(( $b % $a )) $a
      let "n = $?"
   else
      let "n = $b"
   fi
   return $n
}

gcd $1 $2
echo "Greatest common divisor is $?"

Глагол

Деление с остатком, без рекурсии:

ЗАДАЧА НОД (a, b: ЦЕЛ): ЦЕЛ;
УКАЗ
    ПОКА (a # 0) И (b # 0) ВЫП
        ЕСЛИ a >= b ТО
            a := a ОСТАТОК b
        ИНАЧЕ
            b := b ОСТАТОК a
        КОН
    КОН;
    ВОЗВРАТ a + b
КОН НОД;

Ассемблер

ARM

Вычитание, без рекурсии:

loop	CMP Ri, Rj		; проверка условий NE (i != j), GT (i > j) и LT (i < j);
	SUBGT Ri, Ri, Rj	; если GT, выполняется i = i-j;
	SUBLT Rj, Rj, Ri	; если LT, выполняется j = j-i;
	BNE loop		; если NE - переход на метку loop.

Z80

Вычитание, без рекурсии:

GCD_DEHL:        ;CALL Inputs: HL,DE; Output: DE
        AND     A       ;сброс CF
LOOP:
        SBC     HL,DE   ;совмещение трёх в одном - одного сравнения и поочередно двух вычитаний.
        RET     Z       ;минимизация общего размера, поэтому в цикле.
        JR      NC,LOOP
        ADD     HL,DE   ;откат лишнего вычитания
        EX      DE,HL
        JR      GCD_DEHL

Программируемые микрокалькуляторы «Электроника»

Деление с остатком, без рекурсии. Корректно обрабатываются любые целые числа (включая 0 и отрицательные). В вычислениях участвуют только регистры стека.

Использование: <первое число> В↑ <второе число> В/О С/П (НОД на индикаторе).

МК-52 / 61 / 152 / 161

00. Fx≠0   01. 13     02. ↔      03. В↑     04. FВx    05. ÷      06. FВx    07. ↔      08. K[x]   09. ×
10. −      11. Fx=0   12. 02     13. +      14. K|x|   15. С/П

См. также