Эксперт С++
 Аватар для Thinker
4267 / 2241 / 203
Регистрация: 26.08.2011
Сообщений: 3,802
Записей в блоге: 5

Самый быстрый алгоритм Евклида вычисления НОД

13.10.2011, 18:41. Показов 107438. Ответов 44
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Заинтересовал вопрос о различных реализациях алгоритма Евклида для неотрицательных целых чисел. Ниже привожу алгоритмы, собственноручно написанные, исходя из теоретического материала. Каждый алгоритм можно модифицировать в ту или иную сторону.

Считается, что бинарный алгоритм работает быстрее, но мои тесты показывают, что два первых алгоритма работают быстрее бинарного. Может ли кто перепроверить на скорость на своих компиляторах, а то очень интересно и не видится никаких преимуществ бинарного алгоритма.

C
1
2
3
4
5
6
7
8
9
10
//обычный алгоритм Евклида через остатки
long Nod(long a, long b)
{
    while (a && b)
        if (a >= b)
           a %= b;
        else
           b %= a;
    return a | b;
}
C
1
2
3
4
5
6
7
8
9
10
// Алгоритм Евклида через разности
long Nod(long a, long b)
{
    while (a && b)
        if (a >= b)
           a -= b;
        else
           b -= a;
    return a | b;
}

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Бинарный алгоритм Евклида
long Nod(long a, long b)
{
    long deg = 0;
    if (a == 0 || b == 0)
        return a | b;
    while (((a | b) & 1) == 0)
    {
        deg++;
        a >>= 1;
        b >>= 1;
    }
    while (a && b)
    {
        if (b & 1)
            while ((a & 1) == 0)
                a >>= 1;
        else
            while ((b & 1) == 0)
                b >>= 1;
        if (a >= b)
            a = (a - b) >> 1;
        else
            b = (b - a) >> 1;
    }
    return ((a | b) << deg);
}
Еще один бинарный алгоритм, но он самый медленный из всех предыдущих.
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
long Nod(long a, long b)
{
    long buf, deg = 0;
    if (a == 0 || b == 0)
        return a | b;
    while (((a | b) & 1) == 0)
    {
        deg++;
        a >>= 1;
        b >>= 1;
    }
    if (a)
        while ((a & 1) == 0)
            a >>= 1;
    while (b)
    {
        while ((b & 1) == 0)
            b >>= 1;
        if (a < b)
            b -= a;
        else
        {
            buf = a - b;
            a = b;
            b = buf;
        }
        b >>= 1;
    }
    return (a << deg);
}
20
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
13.10.2011, 18:41
Ответы с готовыми решениями:

Найти НОД для одномерного массива, используя алгоритм Евклида
Вопрос в том как найти НОД для одномерного массива, используя алгоритм Евклида?

Найти НОД двух целых положительных чисел А и В, используя алгоритм Евклида
Описать функцию NOD2(A,B) целого типа,находящую наибольший общий делитель(НОД) двух целых положительных чисел А и В,используя алгоритм...

Алгоритм Евклида для вычисления НОД
Алгоритм Евклида для вычисления наибольшего общего делителя двух натуральных чисел, формулируется так: нужно заменять большее число на...

44
0 / 0 / 0
Регистрация: 13.04.2018
Сообщений: 1
29.06.2018, 15:00
Студворк — интернет-сервис помощи студентам
Здравствуйте, если кто ещё бывает на этой теме. Долго разбирался, как действует бинарный алгоритм (не привык я работать с битами).
Насколько я понял, первый цикл while отсекает все степени двойки, а второй фактически работает через разности, с дополнительными циклами, которые должны бы заменить остаток от деления, но в половине случаев простаивают. Попытался оптимизировать как понял:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int gcd(int a, int b)
{   
    char shift_a{}, shift_b{}; // shift_a = 0, shift_b = 0; - для C
    if (a && b)
    {
        while (!(a & 1)) {
            a >>= 1;
            ++shift_a;
        }
 
        while (!(b & 1)) {
            b >>= 1;
            ++shift_b;
        }
 
        while (a && b) a >= b ? a %= b : b %= a;
    }
    return (a | b) << (shift_a <= shift_b ? shift_a : shift_b);
}
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13215 / 6847 / 1826
Регистрация: 18.10.2014
Сообщений: 17,347
30.06.2018, 02:02
Цитата Сообщение от xall Посмотреть сообщение
Долго разбирался, как действует бинарный алгоритм (не привык я работать с битами).
Данная реализация сначала просто-напросто в цикле делит исходные значения на 2 пока они делятся на 2. То, что это деление выражено через битовые сдвиги или битовые проверки никакой роли не играет - это просто манерничанье. При этом запоминается, сколько раз удалось каждое число разделить на 2 (значения shift_a и shift_b)

Дальше применяется обычный Евклидов алгоритм НОД для чисел, которые остались после деления на 2.

Когда мы получили этот НОД, надо просто умножить его на 2min(shift_a, shift_b) - и готов результат. Вот тут действительно полезен побитовый сдвиг.

---

Я бы предположил, что такая оптимизация не имеет большого смысла, пока мы не пользуемся встроенными процессорными средствами для выполнения исходных исчерпывающих делений на 2. Например, для GCC

C
1
2
3
4
5
6
7
8
9
10
11
12
unsigned gcd(unsigned a, unsigned b)
{   
    unsigned shift_a = 0, shift_b = 0;
    if (a && b)
    {
        a >>= (shift_a = __builtin_ctz(a));
        b >>= (shift_b = __builtin_ctz(b));
 
        while (a && b) a >= b ? a %= b : b %= a;
    }
    return (a | b) << (shift_a <= shift_b ? shift_a : shift_b);
}
0
0 / 0 / 0
Регистрация: 17.03.2022
Сообщений: 8
14.05.2022, 11:25
Данные цели положительные числа А и В. Найти их наибольшего общего делителя (НОД),
используя алгоритм Евклида:
НОД(А, В) = НОД(B, A mod В), если В ≠0; НОД(A, 0) = А, где «mod» означает операцию взятия
остатка от деления.

А такое сможете решить?
0
Модератор
Эксперт по электронике
8982 / 6749 / 921
Регистрация: 14.02.2011
Сообщений: 23,876
14.05.2022, 20:54
Цитата Сообщение от spum Посмотреть сообщение
А такое сможете решить?
а тему перечитать?
Самый быстрый алгоритм Евклида вычисления НОД
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13215 / 6847 / 1826
Регистрация: 18.10.2014
Сообщений: 17,347
11.09.2022, 19:58
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Когда мы получили этот НОД, надо просто умножить его на 2min(shift_a, shift_b) - и готов результат. Вот тут действительно полезен побитовый сдвиг.
Эту идею на самом деле можно развить и дальше.

Как только мы знаем, какая степень двойки является общим делителем для исходных значений a и b, промежуточные значения в процессе работы Алгоритма Евклида уже можно делить на 2 (то есть выдвигать из них замыкающие вереницы нулей) ни о чем не беспокоясь - это не приведет к искажению финального значения НОД.

В терминах C++20 получаем что-то вроде

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
unsigned gcd(unsigned a, unsigned b)
{
  unsigned pow2 = std::countr_zero(a | b); // или __builtin_ctz
 
  while (a && b)
  {
    a >>= std::countr_zero(a);
    b >>= std::countr_zero(b);
    a >= b ? a -= b : b -= a;
  }
 
  return (a | b)  << pow2;
}
или

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
unsigned gcd(unsigned a, unsigned b)
{
  unsigned pow2 = std::countr_zero(a | b);
 
  a >>= std::countr_zero(a);
  do 
  {
    b >>= std::countr_zero(b);
 
    if (a > b)
      std::swap(a, b);
 
    b -= a;
 
  } while (b > 0);
 
  return a << pow2;
}
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
11.09.2022, 19:58

Алгоритм Евклида вычисления НОД - проверить корректность вычислений
Проверьте, пожалуйста, мое решение, кому не составит труда? Просто решил, а правильно или нет - могу узнать только здесь от добрых людей :)...

Построить алгоритм Маркова, который ищет НОД (Алгоритм Евклида)
Здравствуйте, ребята, выручайте. Весь инет перерыл, всю голову сломал, но не могу сделать. Суть в чем, надо построить алгорифм Маркова,...

НОД . Рекурсивный алгоритм Евклида
1. Даны два натуральных числа X и Y. Найти их наибольший общий делитель, используя рекурсивный алгоритм Эвклида. Вход: В текстовом...

Алгоритм Евклида для нахождения НОД
Уважаемые форумчане, никак не получается написать алгоритм Евклида, возможно не хватает знаний, возможно опыта. Сам алгоритм я знаю, но как...

НОД двух чисел алгоритм Евклида
Найти найбольший общий делитель двух чисел по алгоритму Евклида. Использовать рекурсию.


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
45
Ответ Создать тему
Опции темы

Новые блоги и статьи
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
Нашел вот забавное видео о измерениях. Лучшее что я видел на эту тему
kumehtar 26.08.2026
ILETXiw9bMQ Основная суть и тезисы по измерениям: 0D (Нулевое измерение): точка, не имеющая длины, ширины, высоты или объема. Объект не может перемещаться в 0D. 1D (Первое измерение):. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru