2012-06-08 8 views
19

Escribo una clase numérica mixta y necesito una función rápida y sencilla de 'máximo divisor común'. ¿Alguien puede darme el código o un enlace al código?Función GCD en la biblioteca C++ sans cmath

+0

Por cierto: se llama 'máximo común divisor'. – bjoernz

+0

Hay muchos más divertidos aquí: http://codegolf.stackexchange.com/questions/35587/ – technosaurus

Respuesta

30

Tengo la tentación de votar para cerrar - parece difícil creer que una implementación sería difícil de encontrar, pero quién sabe con certeza.

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

Gracias. Y busqué en Google durante 20 minutos y no obtuve ningún resultado claro. –

+0

¿Por qué usar unsigned? –

+0

@EnjoysMath: Principalmente porque al menos la mayoría de las veces que quieres usar GCD, tratas con números sin firmar. –

16

Una versión recursiva rápida:

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

o la versión iterativa equivalente si está opusieron violentamente a la recursividad (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; 
} 

Sólo sustituto en su propio tipo de datos, comparación cero, asignación y método de módulo (si está utilizando algún tipo no básico como una clase bignum, por ejemplo).

Esta función en realidad vino de un earlier answer of mine para trabajar relaciones de aspecto integrales para tamaños de pantalla, pero la fuente original fue el algoritmo euclidiano que aprendí hace mucho tiempo, detallado here on Wikipedia si quiere saber las matemáticas detrás de él.


(a) El problema con algunas soluciones recursivas es que se acercan a la respuesta tan lentamente que tienden a quedarse sin espacio de pila antes de llegar allí, por ejemplo, con la muy mal pensado (pseudo- código):

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

Encontrarás que muy caro en algo como sum (1, 1000000000) a medida que (intentar) utiliza un mil millones o menos marcos de pila. El caso de uso ideal para la recursión es algo así como una búsqueda binaria en la que se reduce el espacio de la solución a la mitad para cada iteración. El divisor común más grande también es uno en el que el espacio de solución se reduce rápidamente, por lo que los temores sobre el uso masivo de la pila son infundados allí.

+0

+1 Incluso puede agregar 'template ' para reemplazar el 'int', agregar una palabra clave' constexpr' antes de la función y usted tiene una buena función genérica en tiempo de compilación/tiempo de ejecución. – authchir

+0

Posible error tipográfico en su segundo método. ¿Debería 'devolver n1'? n2 por definición siempre será cero en ese punto. –

+0

Buena captura, @Jim, corrigió eso. – paxdiablo

4

Euclidean El algoritmo es bastante fácil de escribir en C.

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

La biblioteca de algoritmos libstdC++ tiene una función oculta mcd (estoy usando g ++ 4.6.3).

#include <iostream> 
#include <algorithm> 

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

que son bienvenidos :)

ACTUALIZACIÓN: Como @ chema989 señalar que, en C++ 17 hay std::gcd() polivalente con <numeric> cabecera.

+18

No debe confiar en las características no documentadas, ya que pueden cambiar entre las versiones de la biblioteca. – vmrob

+0

¿Está disponible para MSVC? –

+1

@vmrob: De acuerdo. Siempre puede copiar la implementación de STL. Mbt925: hecho. –

-2

Mis dos centavos; algoritmo de Euclides con plantilla usando XOR swap para los tipos de enteros sin signo:

template <class Unsigned> 
Unsigned gcd(Unsigned a, Unsigned b) 
{ 

    static_assert(
     std::numeric_limits<Unsigned>::is_integer && 
     !std::numeric_limits<Unsigned>::is_signed, "Unsigned required."); 

    while (b) 
    { 
     b ^= a; 
     a ^= b; 
     b = (b^a) % a; 
    } 
    return a; 
} 
+0

Sería bueno saber por qué esto se convierte en dv'd. – Sheljohn

+2

Porque intenta hacer el trabajo del compilador. No lo hagas Sabe sobre los intercambios XOR. Es más probable que interfiera con lo que puede hacer por usted (por ejemplo, desenrollar el bucle). – einpoklum

+0

Esto se rompería si intentaste alimentarlo flotando. Si utilizó un intercambio regular en lugar de un xor-swap, eso no sucedería. Además, como dijo @einpoklum, hay otras optimizaciones que no se aplicarán. La CPU puede tener una instrucción de intercambio especial que no se usa debido a los xors. – Pharap

5

para C++ 17 puede utilizar std::gcd se define en la cabecera <numeric>:

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