Функция GCD в C++ без библиотеки cmath

Я пишу смешанный числительный класс и нуждаюсь в быстрой и простой функции "наибольшего общего делителя". Может кто-нибудь дать мне код или ссылку на код?

5 ответов


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

unsigned GCD(unsigned u, unsigned v) {
    while ( v != 0) {
        unsigned r = u % v;
        u = v;
        v = r;
    }
    return u;
}

В C++ 17 или новее, вы можете просто #include <numeric>, и использовать std::gcd (и если вы заботитесь, о gcd, шансы довольно справедливы, что вы будете заинтересованы в std::lcm Это также было добавлено).


библиотека алгоритмов libstdc++ имеет скрытую функцию gcd (я использую g++ 4.6.3).

#include <iostream>
#include <algorithm>

int main()
{
  cout << std::__gcd(100,24);
  return 0;
}

добро пожаловать :)

UPDATE: как отметил @chema989, в C++17 есть std::gcd() функции, доступные с <numeric> заголовок.


быстрая рекурсивная версия:

unsigned int gcd (unsigned int n1, unsigned int n2) {
    return (n2 == 0) ? n1 : gcd (n2, n1 % n2);
}

или эквивалентная итеративная версия, если вы яростно против рекурсии (a):

unsigned int gcd (unsigned int n1, unsigned int n2) {
    unsigned int tmp;
    while (n2 != 0) {
        tmp = n1;
        n1 = n2;
        n2 = tmp % n2;
    }
    return n1;
}

просто замените свой собственный тип данных, нулевое сравнение, назначение и метод модуля (если вы используете какой-то неосновной тип, такой как bignum класс, например).

эта функция на самом деле пришли из мой предыдущий ответ для разработки интегральных соотношений сторон для размеров экрана но первоисточником был евклидов алгоритм, который я выучил давным-давно, подробно вот в Википедии если вы хотите знать математику за это.


(a) проблема с некоторыми рекурсивными решениями заключается в том, что они приближаются к ответу так медленно, что вы, как правило, заканчиваете пространство стека, прежде чем попасть туда, например, с очень плохо продуманным (псевдо-кодом):

def sum (a:unsigned, b:unsigned):
    if b == 0: return a
    return sum (a + 1, b - 1)

вы найдете, что очень дорого на что-то вроде sum (1, 1000000000) as вы (пытаетесь) использовать миллиард или около того кадров стека. Идеальный вариант использования рекурсии-это что-то вроде двоичного поиска, где вы уменьшаете пространство решения наполовину для каждой итерации. Наибольший общий делитель-это также тот, где пространство решений быстро сокращается, поэтому опасения по поводу массового использования стека необоснованны.


для C++17 вы можете использовать std::gcd определены в заголовке <numeric>:

auto res = std::gcd(10, 20);

на Евклидово алгоритм довольно легко написать в C.

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