2012-06-30 42 views
7

Deseo codificar para calcular el valor de pow (a, b)% MOD. Yo uso C++ para codificar.Cálculo (a^b)% MOD

Pero el problema es que el valor de b puede ser muy grande. Conozco el método log (b) time complexity. Pero, el valor de b podría no ajustarse en el tipo de datos "long long" de C++. Por ejemplo, b puede ser 1000000000 del número de Fibonacci. El cálculo exacto de un número tan grande es en sí mismo, no es posible (en límites de tiempo).

P.S. :

  • pow (a, b) significa a * a * a * a * ... b veces.
  • X% MOD significa el resto obtenido al dividir X por MOD.
+0

posible duplicado de [Manejar enteros de longitud arbitraria en C++] (http://stackoverflow.com/questions/8146938/handle-arbitrary-length-integers-in-c) –

+0

solo para aclarar, en C++ '^' es el operato XOR r, no es un operador exponente (terminarías con algunos resultados bastante bonitos, experiencia de primera mano allí). Creo que tienes que usar 'Math.exp (a, b)' – nbrooks

+0

@nbrooks: Si bien es cierto que C++ usa '^' para significar XOR, 'Math.exp (a, b)' no se ve como C++ (y basado en el nombre, esperaría que calcule el exponencial, no eleve un número a una potencia). –

Respuesta

11

Esa es una tarea típica. Por favor (o, realmente, ¡POR FAVOR!) Lea sobre el Euler's totient function.

Y luego el Euler's theorem.

El problema es que se puede reducir drásticamente a^b a a^(b% phi (MOD)). Sí, necesitará algún tipo de método de factorización de enteros, pero aún así, no hay ideas locas acerca de calcular realmente la potencia necesaria.

Hicimos tales muestras a mano en mi juventud :) Incluso cuando los números eran mucho más allá del rango de 32/64 bits.

EDITAR: Bueno, vives y aprendes. En 2008 se obtiene el resultado:

"El totient es la transformada de Fourier discreta de la mcd: (Schramm (2008))"

Así que para calcular phi (b) uno no necesita saber sus factores.

EDITAR (2):

Y el Carmichael's function es lo que necesita para calcular para obtener la respuesta correcta para todo a, b y MOD.

+0

Gracias Viktor. Obtuve lo que deseaba. Gracias por la ayuda ... :-) Por cierto, sabía acerca de la función totient, pero no sobre el teorema de Euler ... –

+1

"Así que para calcular phi (b) no es necesario conocer sus factores". Sin embargo, esto no parece un método práctico para calcular 'phi (b)'. –

+0

@MarkDickinson: Sí, es por eso que agregué el comentario sobre el trabajo de Schramm. Solo hay una sola transformada discreta de Fourier involucrada. –

0

Primero: ^ en C/C++ es no el operador de poderes. De hecho, no hay operador para esto. ^ representa un bit XOR. Tendrá que usar pow(base, exp) que se puede encontrar en el encabezado math.h o cmath.

Para tales números enormes, utilizando double o long double (longitudes exactas y tipos de datos resultante y podrían variar dependiendo de la plataforma), pero en algún momento se encontrará con problemas de precisión, por lo que dependiendo de su caso de uso, el tamaño de los valores su mejor opción podría ser usar un tipo de datos personalizado (editar: por ejemplo, de una de las bibliotecas encontradas en una de las preguntas vinculadas).

+0

Realmente es una pregunta de teoría de números. No hay necesidad de fuerza bruta aquí.El objetivo de la tarea es mostrar la superioridad de algunos teoremas clásicos simples. Ver mi respuesta –

+0

Interesante, supongo que me robaste el tiempo libre de mi fin de semana, vas a leer sobre eso. :) – Mario

+0

Este libro es bueno: http://books.google.ru/books/about/Number_Theory.html?id=njgVUjjO-EAC También los libros de Ivan Vinogradov son buenos. El "Curso de aritmética" de Jean-Pierre Serre abre aún más posibilidades. –

0

Sugiero usar una biblioteca matemática especializada. También esto parece crypto, entonces sugiero usar una biblioteca crypto. GNU está obligado a tener uno que pueda usar. Esto se debe a que en la criptografía, en muchos casos, el exponente puede seleccionarse para ofrecer un cálculo eficiente utilizando atajos que las bibliotecas matemáticas normales no pueden asumir.

1

Para manejar números muy grandes, eche un vistazo a la biblioteca boost's Multiprecision. Tiene una función powm() que funciona bien para este propósito.

De Generic Integer Operations:

template <class Integer> 
Integer powm(const Integer& b, const Integer& p, const Integer& m); 

devoluciones b p% m.

Ejemplo:

#include <boost/multiprecision/cpp_int.hpp> 

boost::multiprecision::cpp_int pow("8912627233012800753578052027888001981"); 
boost::multiprecision::cpp_int mod("0x86f71688cdd2612c117d1f54bdae029"); 
boost::multiprecision::cpp_int base(12345); 

boost::multiprecision::cpp_int result = powm(base, pow, mod); 

std::cout << "result is: " << result << std::endl; 

impresiones:

result is: 5758534182572671080415167723795472693 
0

embargo, el valor de b puede no encajar en el tipo de datos "long long" de C++. Por ejemplo, b puede ser 1000000000 del número de Fibonacci.

Por cosas como esta, hay una solución sencilla: recordar

un^(b + c) ==^un b * a^c mod d

Puede calcule el producto particular que solicitó con el mismo tipo de recursión que utiliza para calcular los números de Fibonacci: ¡no necesita números grandes ni exponenciación modular en absoluto!

Otra versión que aparece a veces es

a^(b * c) = (a^b)^c mod d

-1
#include <iostream> 
#include <math.h> 
#include <stdint.h> 

using namespace std; 

int main(){ 
int64_t a, b, k, d; 
cin >> a >> b >> k; 

int64_t poew = pow(a, b); 
d = poew % k; 

cout << d; 
} 

porque int64_t tiene un rango mayor que int

+0

La pregunta dice que el valor de 'b' puede ser muy grande y, por lo tanto, pow (a, b) puede no funcionar incluso en una estructura de datos de 64 bits de longitud. –