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

Материал из Викиучебника — открытых книг для открытого мира
Содержимое удалено Содержимое добавлено
→‎BASIC: Оптимизации
Усовершенствования алгоритма для разных языков
Строка 27: Строка 27:


==[[w:Бейсик|BASIC]]==
==[[w:Бейсик|BASIC]]==
===[[w:Dartmouth_BASIC|Оригинальный BASIC]]===
===Оригинальный (Dartmouth BASIC)===
Цикл, вычитание (операция нахождения остатка MOD отсутствовала в этой версии языка):
Цикл, вычитание (операция нахождения остатка MOD отсутствовала в этой версии языка):
<source lang="basic">
<source lang="basic">
10 INPUT "Two integer numbers", A, B
10 PRINT "Two integer numbers";
20 PRINT "GCD("; A; ", "; B,") = ";
20 INPUT A, B
30 PRINT "GCD("; A; ", "; B,") = ";
30 LET A = ABS(A): LET B = ABS(B)
40 LET A = ABS(A)
40 IF B = 0 THEN GOTO 90
50 IF B = 0 THEN GOTO 120
60 LET B = ABS(B)
50 IF A >= B THEN LET A = A - B: GOTO 50
60 IF A = 0 THEN LET A = B: GOTO 90
70 IF A < B THEN GOTO 90
70 LET B = B - A: IF B >= A THEN GOTO 70
80 LET A = A - B: GOTO 70
80 IF B <> 0 THEN GOTO 50
90 IF A = 0 THEN LET A = B: GOTO 120
100 LET B = B - A: IF B >= A THEN GOTO 100
90 PRINT A
110 IF B > 0 THEN GOTO 80
100 END
120 PRINT A
130 END
</source>
</source>


===[[w:GW-BASIC|GW-BASIC]] и совместимые диалекты===
===[[w:GW-BASIC|GW-BASIC]] и совместимые диалекты===
Цикл, деление с остатком либо вычитание (при указанных заменах в коде).
Цикл, деление с остатком:
<source lang="basic">
<source lang="basic">
10 INPUT "Two integer numbers", A%, B%
10 INPUT "Two integer numbers", A%, B%
20 PRINT "GCD("; A%; ", "; B%; ") = ";
20 PRINT "GCD("; A%; ", "; B%; ") = ";
30 A% = ABS(A%): B% = ABS(B%)
30 WHILE B% <> 0
40 WHILE B% > 0
40 A% = A% MOD B%
50 A% = A% MOD B% 'Для вычитания заменить на WHILE A% >= B%: A% = A% - B%: WEND
50 IF A% = 0 THEN A% = B%: B% = 0: ELSE B% = B% MOD A%
60 WEND
60 IF A% = 0 THEN A% = B%: GOTO 90
70 PRINT ABS(A%)
70 B% = B% MOD A% 'Для вычитания заменить на WHILE B% >= A%: B% = B% - A%: WEND
80 WEND
90 PRINT A%
</source>
</source>


===[[w:QuickBasic|QuickBasic]] версий < 4.0, [[w:Turbo Basic|Turbo Basic]]===
===[[w:QuickBasic|QuickBasic]] версий < 4.0, [[w:Turbo Basic|Turbo Basic]]===
Цикл, деление с остатком либо вычитание (при указанных заменах в коде).
Цикл, деление с остатком:
<source lang="basic">
<source lang="basic">
DEF FNGCD%(A%, B%)
DEF FNGCD%(A%, B%)
A% = ABS(A%)
DO UNTIL B% = 0
B% = ABS(B%)
DO WHILE B% > 0
A% = A% MOD B%
A% = A% MOD B%
'Для вычитания убрать предыдущую строку и раскомментировать следующие:
'DO UNTIL A% < B%
' A% = A% - B%
'LOOP
IF A% = 0 THEN
IF A% = 0 THEN
FNGCD% = B%
FNGCD% = ABS(B%)
EXIT DEF
EXIT DEF
END IF
END IF
B% = B% MOD A%
B% = B% MOD A%
'Для вычитания убрать предыдущую строку и раскомментировать следующие:
'DO 'Перед входом в этот цикл 0 < A% < B%, поэтому проверка B% < A% вынесена в постусловие
' B% = B% - A%
'LOOP UNTIL B% < A%
LOOP
LOOP
FNGCD% = A%
FNGCD% = ABS(A%)
END DEF
END DEF
</source>
</source>
Строка 85: Строка 76:
В следующих примерах используется тип <code>Long</code> (длинное целое); вместо него можно применять также тип <code>Integer</code> (стандартное целое).
В следующих примерах используется тип <code>Long</code> (длинное целое); вместо него можно применять также тип <code>Integer</code> (стандартное целое).


Цикл, деление с остатком либо вычитание (при указанных заменах в коде):
Цикл, деление с остатком:
<source lang="vb">
<source lang="vb">
Function GCD(a As Long, b As Long) As Long
Function GCD(a As Long, b As Long) As Long
Do Until b = 0
a = Abs(a)
b = Abs(b)
Do While b > 0
a = a Mod b
a = a Mod b
'Для вычитания убрать предыдущую строку и раскомментировать следующие:
'Do Until a < b
' a = a - b
'Loop
If a = 0 Then
If a = 0 Then
GCD = b
GCD = b
Строка 101: Строка 86:
End If
End If
b = b Mod a
b = b Mod a
'Для вычитания убрать предыдущую строку и раскомментировать следующие:
'Do 'Перед входом в этот цикл 0 < a < b, поэтому проверка b < a вынесена в постусловие
' b = b - a
'Loop Until b < a
Loop
Loop
GCD = a
GCD = a
Строка 113: Строка 94:
<source lang="vb">
<source lang="vb">
Function GCD(a As Long, b As Long) As Long
Function GCD(a As Long, b As Long) As Long
If b = 0 Then
If b = 0 Then
GCD = Abs(a)
GCD = Abs(a)
Else
Else
GCD = GCD(b, a Mod b)
GCD = GCD(b, a Mod b)
End If
End If
End Function
End Function
</source>
</source>


===[[w:VB.NET|VB.NET]]===
===[[w:VB.NET|Visual Basic .NET]]===
В следующих примерах используется тип <code>Long</code> (длинное целое); вместо него можно применять любые другие целочисленные типы платформы [[w:NET_Framework|.NET]].
В следующих примерах используется тип <code>Long</code> (длинное целое); вместо него можно применять любые другие целочисленные типы платформы [[w:NET_Framework|.NET]].


Цикл, деление с остатком либо вычитание (при указанных заменах в коде):
Цикл, деление с остатком:
<source lang="vb">
<source lang="vb">
Shared Function GCD(ByVal a As Long, ByVal b As Long) As Long
Function GCD(ByVal a As Long, ByVal b As Long) As Long
Do Until b = 0
a = Math.Abs(a)
b = Math.Abs(b)
Do While b > 0
a = a Mod b
a = a Mod b
If a = 0 Then Return Math.Abs(b)
'Для вычитания убрать предыдущую строку и раскомментировать следующие:
'Do Until a < b
' a -= b
'Loop
If a = 0 Then Return b
b = b Mod a
b = b Mod a
'Для вычитания убрать предыдущую строку и раскомментировать следующие:
'Do 'Перед входом в этот цикл 0 < a < b, поэтому проверка b < a вынесена в постусловие
' b -= a
'Loop Until b < a
Loop
Loop
Return a
Return Math.Abs(a)
End Function
End Function
</source>
</source>


Рекурсия, деление с остатком либо вычитание (при указанных заменах в коде):
Рекурсия, деление с остатком:
<source lang="vb">
<source lang="vb">
Shared Function GCD (ByVal a As Long, ByVal b As Long) As Long
Function GCD(ByVal a As Long, ByVal b As Long) As Long
Return If(b = 0, Math.Abs(a), GCD(b, a Mod b)) ' VB.NET 2008 или более поздняя версия
If b = 0 Then Return Math.Abs(a)
Return GCD(b, a Mod b)
'Для вычитания убрать предыдущую строку и раскомментировать следующие:
'If a >= b Then Return GCD(a, a - b)
'Return GCD(b, b - a)
End Function
End Function
</source>
</source>


==[[w:C (язык программирования)|C]]/[[w:C++|C++]]==
==[[w:C (язык программирования)|C]]/[[w:C++|C++]]==
'''C:''' Тип <code>IntType</code> должен быть задан как:
'''C:''' Тип <code>Integer</code> должен быть задан как:
<source lang="c">typedef int IntType; /* Вместо int можно подставить любой другой целочисленный тип */</source>
<source lang="c">typedef int Integer; /* Вместо int можно подставить любой другой целочисленный тип */</source>


'''C++:''' Любую из нижеприведённых функций (включая <code>abs</code>) следует предварить строкой:
'''C++:''' Любую из нижеприведённых функций (включая <code>abs</code>) следует предварить строкой:
<source lang="cpp">template < typename IntType ></source>
<source lang="cpp">template <typename Integer></source>
Для корректной обработки отрицательных чисел все последующие примеры на C/C++ используют функцию вычисления модуля числа:
Для корректной обработки отрицательных чисел все последующие примеры на C/C++ используют функцию вычисления модуля числа:
<source lang="c">
<source lang="c">
IntType abs (IntType value) {
Integer abs (Integer value) {
return (value < 0) ? -value : value;
return (value < 0) ? -value : value;
}
}
</source>
</source>


Деление с остатком, цикл:
Деление с остатком, цикл:

<source lang="c">
<source lang="c">
IntType gcd (IntType a, IntType b) {
Integer gcd (Integer a, Integer b) {
for (Integer c; b; ) {
IntType c;
while (b) {
c = a % b;
c = a % b;
a = b;
a = b;
b = c;
}
b = c;
return abs(a);
}
}
return abs(a);
</source>

Без использования дополнительной переменной:
<source lang="c">
Integer gcd (Integer a, Integer b) {
while (b)
b ^= a ^= b ^= a %= b;
return abs(a);
}
}
</source>
</source>


Без использования дополнительной переменной и с наименьшим числом сравнений и присваиваний:
Более короткое решение:
<source lang="c">
<source lang="c">
IntType gcd (IntType a, IntType b) {
Integer gcd (Integer a, Integer b) {
while (b)
if (!a)
return abs(b);
b ^= a ^= b ^= a %= b;
return abs(a);
if (!b)
return abs(a);
for ( ; ; )
if (!(a %= b))
return abs(b);
else if (!(b %= a))
return abs(a);
}
}
</source>
</source>
Строка 194: Строка 176:
Деление с остатком, рекурсия:
Деление с остатком, рекурсия:
<source lang="c">
<source lang="c">
IntType gcd (IntType a, IntType b) {
Integer gcd (Integer a, Integer b) {
return (b == 0) ? abs(a) : gcd(b, a % b);
return !b ? abs(a) : gcd(b, a % b);
}
}
</source>
</source>
Строка 201: Строка 183:
Вычитание, цикл:
Вычитание, цикл:
<source lang="c">
<source lang="c">
IntType gcd (IntType a, IntType b) {
Integer gcd (Integer a, Integer b) {
a = abs(a);
a = abs(a);
b = abs(b);
b = abs(b);
while (a != b) {
while (b) {
if (a > b)
while (a >= b)
a -= b;
a -= b;
if (!a)
else
return b;
b -= a;
do {
b -= a;
} while (b >= a);
}
}
return a;
return a;
Строка 214: Строка 199:
</source>
</source>


==[[w:C_Sharp|C#]], [[w:Java|Java]]==
==[[w:C_Sharp|C#]], [[w:Java|Java]]<ref>Для соответствия правилам оформления кода Java метод следует переименовать в <code>gcd</code> и перенести <code>{</code> в конец предыдущей строки</ref>==
Приведён код для C#. Для Java следует заменить <code>Abs</code> на <code>abs</code> и, для соответствия правилам оформления кода, переименовать функции в <code>gcd</code> и перенести <code>{</code> в конец предыдущей строки.

Вместо <code>long</code> можно использовать и другие целочисленные типы — <code>byte</code>, <code>int</code> и т. д.
Вместо <code>long</code> можно использовать и другие целочисленные типы — <code>byte</code>, <code>int</code> и т. д.


Деление с остатком, цикл:
Деление с остатком, цикл:
<source lang="csharp">
<source lang="csharp">
static long GCD (long a, long b)
static long GCD(long a, long b)
{
{
while (b != 0)
while (b != 0)
b = a % (a = b);
b = a % (a = b);
return a < 0 ? -a : a;
return Math.Abs(a);
}
</source>

<source lang="csharp">
static long GCD(long a, long b)
{
if (a == 0)
return Math.Abs(b);
if (b == 0)
return Math.Abs(a);
for ( ; ; ) {
if ((a %= b) == 0)
return Math.Abs(b);
if ((b %= a) == 0)
return Math.Abs(a);
}
}
}
</source>
</source>
Строка 231: Строка 234:
static long GCD (long a, long b)
static long GCD (long a, long b)
{
{
return b == 0 ? (a < 0 ? -a : a) : GCD(b, a % b);
return b == 0 ? Math.Abs(a) : GCD(b, a % b);
}
}
</source>
</source>
Строка 260: Строка 263:
Тип <code>IntType</code> определён как:
Тип <code>IntType</code> определён как:
<source lang="go">
<source lang="go">
type IntType = int // Вместо int можно подставить любой другой целочисленный тип
type Integer = int // Вместо int можно подставить любой другой целочисленный тип
</source>
</source>


Для корректной обработки отрицательных чисел все последующие примеры на Go используют функцию вычисления модуля числа:
Для корректной обработки отрицательных чисел все последующие примеры на Go используют функцию вычисления модуля числа:
<source lang="go">
<source lang="go">
func IntAbs(value IntType) IntType {
func IntAbs(value Integer) Integer {
if value < 0 {
if value < 0 {
return -value
return -value
Строка 275: Строка 278:
Деление с остатком, цикл:
Деление с остатком, цикл:
<source lang="go">
<source lang="go">
func GCD(a, b IntType) IntType {
func GCD(a, b Integer) Integer {
for b != 0 {
for b != 0 {
a %= b
a %= b
Строка 287: Строка 290:
</source>
</source>


Деление с остатком, рекурсия:
Вычитание, цикл:
<source lang="go">
<source lang="go">
func GCD(a, b IntType) IntType {
func GCD(a, b Integer) Integer {
if b == 0 {
a = IntAbs(a)
b = IntAbs(b)
return IntAbs(a)
for b != 0 {
for a >= b {
a -= b
}
if a == 0 {
return b
}
for b >= a {
b -= a
}
}
}
return a
return GCD(b, a % b)
}
}
</source>
</source>
Строка 318: Строка 311:


==[[w:Паскаль (язык программирования)|Pascal]]==
==[[w:Паскаль (язык программирования)|Pascal]]==
Тип <code>IntType</code> определён как:
Тип <code>TInteger</code> определён как:
<source lang="pascal">
<source lang="pascal">
type IntType = Integer; { Вместо Integer можно подставить любой другой целочисленный тип }
type TInteger = Integer; { Вместо Integer можно подставить любой другой целочисленный тип }
</source>
</source>


Деление с остатком, цикл:
Деление с остатком, цикл:
<source lang="pascal">
<source lang="pascal">
function GCD (a, b: IntType): IntType;
function GCD(a, b: TInteger): TInteger;
begin
while a * b <> 0 do
if a > b then
a := a mod b
else
b := b mod a;
GCD := Abs(a + b)
end;
</source>

Более быстрый алгоритм:
<source lang="pascal">
function GCD (a, b: IntType): IntType;
var c: IntType;
begin
begin
while b > 0 do
while b <> 0 do
begin
begin
c := a mod b;
a := a mod b;
a := b;
if a = 0 then
begin
b := c
end;
a := b;
GCD := Abs(a)
b := 0
end
else
b := b mod a
end;
GCD := Abs(a)
end;
end;
</source>
</source>
Строка 353: Строка 337:
Деление с остатком, рекурсия:
Деление с остатком, рекурсия:
<source lang="pascal">
<source lang="pascal">
function GCD (a, b: IntType): IntType;
function GCD(a, b: TInteger): TInteger;
begin
begin
if b = 0 then
if b = 0 then
GCD := Abs(a)
GCD := Abs(a)
else
else
GCD := GCD(b, a mod b)
GCD := GCD(b, a mod b)
end;
end;
</source>
</source>
Строка 366: Строка 350:
<source lang="perl">
<source lang="perl">
sub gcd {
sub gcd {
return $_[0] != 0 ? gcd ( ( $_[1] % $_[0] ), $_[0] ) : $_[1];
return $_[0] != 0 ? gcd ( ( $_[1] % $_[0] ), $_[0] ) : $_[1];
}
}
</source>
</source>
Строка 374: Строка 358:
<source lang="php">
<source lang="php">
function gcd ($a, $b) {
function gcd ($a, $b) {
while ($a <> 0 && $b <> 0) {
if ($a === 0)
return abs($b);
if ($a > $b)
if ($b === 0)
$a = $a % $b;
return abs($a)
else
for ( ; ; )
$b = $b % $a;
if (($a %= $b) === 0)
}
return abs($a + $b);
return abs($b);
else if (($b %= $a) === 0)
return abs($a);
}
}
echo gcd(5, 3);
echo gcd(5, 3);
Строка 409: Строка 395:
Деление с остатком, цикл:
Деление с остатком, цикл:
<source lang="python">
<source lang="python">
def gcd (a, b):
def gcd(a: int, b: int) -> int:
while b:
while b:
a, b = b, a % b
a, b = b, a % b
return abs(a)
return abs(a)
</source>
</source>


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


Строка 424: Строка 410:
Деление с остатком, цикл:
Деление с остатком, цикл:
<source lang="ruby">
<source lang="ruby">
def gcd (a, b)
def gcd(a, b)
a, b = b, a % b until b.zero?
a, b = b, a % b until b.zero?
a.abs
a.abs
end
end
</source>
</source>
Строка 432: Строка 418:
Деление с остатком, рекурсия:
Деление с остатком, рекурсия:
<source lang="ruby">
<source lang="ruby">
def gcd (a, b)
def gcd(a, b)
return a.abs if b.zero?
return a.abs if b.zero?
gcd(b, a % b)
gcd(b, a % b)
end
</source>

Вычитание, цикл:
<source lang="ruby">
def gcd (a, b)
a = a.abs
b = b.abs
if a > b
a -= b
else
b -= a
end while a != b
a
end
end
</source>
</source>
Строка 463: Строка 435:
pub fn gcd <IntType> (mut a: IntType, mut b: IntType) -> IntType
pub fn gcd <IntType> (mut a: IntType, mut b: IntType) -> IntType
where IntType: Copy + FromPrimitive + PartialEq + Rem<Output = IntType> {
where IntType: Copy + FromPrimitive + PartialEq + Rem<Output = IntType> {
let zero = FromPrimitive::from_u32(0u32).unwrap(); // Обобщённая константа 0
let zero = FromPrimitive::from_u32(0u32).unwrap(); // Обобщённая константа 0
let mut c: IntType;
let mut c: IntType;
while b != zero {
while b != zero {
c = a % b;
c = a % b;
a = b;
a = b;
b = c;
b = c;
}
}
a
a
}
}
</source>
</source>
Строка 480: Строка 452:


pub fn gcd <T: Copy + PartialOrd + SubAssign> (mut a: T, mut b: T) -> T {
pub fn gcd <T: Copy + PartialOrd + SubAssign> (mut a: T, mut b: T) -> T {
while a != b {
while a != b {
if a > b {
if a > b {
a -= b;
a -= b;
} else {
} else {
b -= a;
b -= a;
}
}
}
}
a
a
}
}
</source>
</source>
Строка 502: Строка 474:
<source lang="bash">
<source lang="bash">
gcd () {
gcd () {
n = 1 a = $1 b = $2
n = 1 a = $1 b = $2
if [[ $a -ne 0 ]]
if [[ $a -ne 0 ]]
then
then
gcd $(( $b % $a )) $a
gcd $(( $b % $a )) $a
let "n = $?"
let "n = $?"
else
else
let "n = $b"
let "n = $b"
fi
fi
return $n
return $n
}
}


Строка 522: Строка 494:
ЗАДАЧА НОД (a, b: ЦЕЛ): ЦЕЛ;
ЗАДАЧА НОД (a, b: ЦЕЛ): ЦЕЛ;
УКАЗ
УКАЗ
ПОКА (a # 0) И (b # 0) ВЫП
ПОКА b # 0 ВЫП
a := a ОСТАТОК b;
ЕСЛИ a < b ТО
ЕСЛИ a = 0 ТО
b := b ОСТАТОК a
ИНАЧЕ
a := b;
b := 0
a := a ОСТАТОК b
ИНАЧЕ
b := b ОСТАТОК a
КОН
КОН
КОН;
КОН;
ВОЗВРАТ МОДУЛЬ(a + b)
ВОЗВРАТ МОДУЛЬ(a)
КОН НОД;
КОН НОД;
</source>
</source>

Версия от 06:29, 3 августа 2019

Реализации алгоритма Евклида для вычисления НОД — наибольшего общего делителя (англ. GCD — greatest common divisor) двух целых чисел на различных языках программирования.

Реализации

Assembler

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

BASIC

Оригинальный (Dartmouth BASIC)

Цикл, вычитание (операция нахождения остатка MOD отсутствовала в этой версии языка):

10 PRINT "Two integer numbers";
20 INPUT A, B
30 PRINT "GCD("; A; ", "; B,") = ";
40 LET A = ABS(A)
50 IF B = 0 THEN GOTO 120
60 LET B = ABS(B)
70 IF A < B THEN GOTO 90
80 LET A = A - B: GOTO 70
90 IF A = 0 THEN LET A = B: GOTO 120
100 LET B = B - A: IF B >= A THEN GOTO 100
110 IF B > 0 THEN GOTO 80
120 PRINT A
130 END

GW-BASIC и совместимые диалекты

Цикл, деление с остатком:

10 INPUT "Two integer numbers", A%, B%
20 PRINT "GCD("; A%; ", "; B%; ") = ";
30 WHILE B% <> 0
40 A% = A% MOD B%
50 IF A% = 0 THEN A% = B%: B% = 0: ELSE B% = B% MOD A%
60 WEND
70 PRINT ABS(A%)

QuickBasic версий < 4.0, Turbo Basic

Цикл, деление с остатком:

DEF FNGCD%(A%, B%)
	DO UNTIL B% = 0
		A% = A% MOD B%
		IF A% = 0 THEN
			FNGCD% = ABS(B%)
			EXIT DEF
		END IF
		B% = B% MOD A%
	LOOP
	FNGCD% = ABS(A%)
END DEF

PowerBASIC, QBASIC, QuickBasic версий ≥ 4.0, Visual Basic

В следующих примерах используется тип Long (длинное целое); вместо него можно применять также тип Integer (стандартное целое).

Цикл, деление с остатком:

Function GCD(a As Long, b As Long) As Long
	Do Until b = 0
		a = a Mod b
		If a = 0 Then
			GCD = b
			Exit Function
		End If
		b = b Mod a
	Loop
	GCD = a
End Function

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

Function GCD(a As Long, b As Long) As Long
	If b = 0 Then
		GCD = Abs(a)
	Else
		GCD = GCD(b, a Mod b)
	End If
End Function

Visual Basic .NET

В следующих примерах используется тип Long (длинное целое); вместо него можно применять любые другие целочисленные типы платформы .NET.

Цикл, деление с остатком:

Function GCD(ByVal a As Long, ByVal b As Long) As Long
	Do Until b = 0
		a = a Mod b
		If a = 0 Then Return Math.Abs(b)
		b = b Mod a
	Loop
	Return Math.Abs(a)
End Function

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

Function GCD(ByVal a As Long, ByVal b As Long) As Long
	Return If(b = 0, Math.Abs(a), GCD(b, a Mod b)) ' VB.NET 2008 или более поздняя версия
End Function

C/C++

C: Тип Integer должен быть задан как:

typedef int Integer; /* Вместо int можно подставить любой другой целочисленный тип */

C++: Любую из нижеприведённых функций (включая abs) следует предварить строкой:

template <typename Integer>

Для корректной обработки отрицательных чисел все последующие примеры на C/C++ используют функцию вычисления модуля числа:

Integer abs (Integer value) {
	return (value < 0) ? -value : value;
}

Деление с остатком, цикл:

Integer gcd (Integer a, Integer b) {
	for (Integer c; b; ) {
		c = a % b;
		a = b;
		b = c;
	}
	return abs(a);
}

Без использования дополнительной переменной:

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

Без использования дополнительной переменной и с наименьшим числом сравнений и присваиваний:

Integer gcd (Integer a, Integer b) {
	if (!a)
		return abs(b);
	if (!b)
		return abs(a);
	for ( ; ; )
		if (!(a %= b))
			return abs(b);
		else if (!(b %= a))
			return abs(a);
}

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

Integer gcd (Integer a, Integer b) {
	return !b ? abs(a) : gcd(b, a % b);
}

Вычитание, цикл:

Integer gcd (Integer a, Integer b) {
	a = abs(a);
	b = abs(b);
	while (b) {
		while (a >= b)
			a -= b;
		if (!a)
			return b;
		do {
			b -= a;
		} while (b >= a);
    }
    return a;
}

C#, Java

Приведён код для C#. Для Java следует заменить Abs на abs и, для соответствия правилам оформления кода, переименовать функции в gcd и перенести { в конец предыдущей строки.

Вместо long можно использовать и другие целочисленные типы — byte, int и т. д.

Деление с остатком, цикл:

static long GCD(long a, long b)
{
    while (b != 0)
        b = a % (a = b);
    return Math.Abs(a);
}
static long GCD(long a, long b)
{
	if (a == 0)
		return Math.Abs(b);
	if (b == 0)
		return Math.Abs(a);
	for ( ; ; ) {
		if ((a %= b) == 0)
			return Math.Abs(b);
		if ((b %= a) == 0)
			return Math.Abs(a);
	}
}

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

static long GCD (long a, long b)
{
    return b == 0 ? Math.Abs(a) : GCD(b, a % b);
}

Erlang

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

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

F#

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

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

Forth (диалект RetroForth)

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

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

Go

Тип IntType определён как:

type Integer = int // Вместо int можно подставить любой другой целочисленный тип

Для корректной обработки отрицательных чисел все последующие примеры на Go используют функцию вычисления модуля числа:

func IntAbs(value Integer) Integer {
	if value < 0 {
		return -value
	}
	return value
}

Деление с остатком, цикл:

func GCD(a, b Integer) Integer {
	for b != 0 {
		a %= b
		if a == 0 {
			return IntAbs(b)
		}
		b %= a
	}
	return IntAbs(a)
}

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

func GCD(a, b Integer) Integer {
	if b == 0 {
		return IntAbs(a)
	}
	return GCD(b, a % b)
}

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)

Pascal

Тип TInteger определён как:

type TInteger = Integer; { Вместо Integer можно подставить любой другой целочисленный тип }

Деление с остатком, цикл:

function GCD(a, b: TInteger): TInteger;
begin
	while b <> 0 do
	begin
		a := a mod b;
		if a = 0 then
		begin
			a := b;
			b := 0
		end
		else
			b := b mod a
	end;
	GCD := Abs(a)
end;

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

function GCD(a, b: TInteger): TInteger;
begin
	if b = 0 then
		GCD := Abs(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) {
	if ($a === 0)
		return abs($b);
	if ($b === 0)
		return abs($a)
	for ( ; ; )
		if (($a %= $b) === 0)
			return abs($b);
		else if (($b %= $a) === 0)
			return abs($a);
}
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)

w: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).

Python

Деление с остатком, цикл:

def gcd(a: int, b: int) -> int:
	while b:
		a, b = b, a % b
	return abs(a)

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

def gcd(a: int, b: int) -> int:
	return abs(a) if b == 0 else gcd(b, a % b)

Ruby

Деление с остатком, цикл:

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

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

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

Rust

Деление с остатком, цикл:

extern crate num;

use self::num::FromPrimitive;
use std::ops::Rem;


pub fn gcd <IntType> (mut a: IntType, mut b: IntType) -> IntType
where IntType: Copy + FromPrimitive + PartialEq + Rem<Output = IntType> {
	let zero = FromPrimitive::from_u32(0u32).unwrap(); // Обобщённая константа 0
	let mut c: IntType;
	while b != zero {
		c = a % b;
		a = b;
		b = c;
	}
	a
}

Вычитание, цикл:

use std::ops::SubAssign;


pub fn gcd <T: Copy + PartialOrd + SubAssign> (mut a: T, mut b: T) -> T {
	while a != b {
		if a > b {
			a -= b;
		} else {
			b -= a;
		}
	}
	a
}

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: ЦЕЛ): ЦЕЛ;
УКАЗ
	ПОКА b # 0 ВЫП
		a := a ОСТАТОК b;
		ЕСЛИ a = 0 ТО
        	a := b;
			b := 0
		ИНАЧЕ
			b := b ОСТАТОК a
        КОН
    КОН;
    ВОЗВРАТ МОДУЛЬ(a)
КОН НОД;

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

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

МК-61 / 52 / 152 / 161 / 163 / 1152

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

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. С/П

Б3-34, МК-54 / 56 / 61 / 52 / 152 / 161 / 163 / 1152

Вычитание, цикл. Корректно обрабатываются любые целые неотрицательные числа. В вычислениях участвуют только регистры стека X и Y.

00. −      01. Fx≠0   02. 12     03. Fx<0   04. 09     05. FВx    06. ↔      07. /−/    08. −      09. FВx
10. БП     11. 00     12. FВx    13. С/П

Б3-21, МК-46 / 64, МС-1103

Вычитание, цикл. Корректно обрабатываются любые целые неотрицательные числа. В вычислениях участвуют только регистры стека X и Y.

00. Px≠0   01. ↔      02. −      03. Px≥0   04. F1     05. ↔
10. −      11. /−/    12. ↔      13. Px=0   14. Peⁱˣ   15. ↔
20. С/П

См. также

Ссылки