Welcome, guest | Sign In | My Account | Store | Cart
/* Alumno: Guillermo López Leal 2IM1
 * 
 * Karatsuba algorith: fast multiplication of large integers.
 * 
 * Sorry for the comments in Spanish, but I think the code is very legible ;)
 */
#include <iostream>
#include <math .h>
 
using namespace std;
 
/*
 * Función Power(double x, int y)
 * calcula el número que resulta de calcular
 * x elevado a y. Se realiza por recursión.
 * Devuelve un tipo T, que se supone será
 * un número: int, double, float...
 *
 */
int Power(int x, int y) {
	if (y == 0)
		return (1);
	else if (y == 1)
		return(x);
	else
		return(x * Power(x, y-1));
}
 
/*
 * Función Digitos (T n, int &dig)
 * calcula el número de dígitos (dig) que tiene el número n, que
 * podría ser cualquier tipo de número: int, float, double...
 * Devuelve el número de dígitos (int).
 * He preferido cambiar la función para que devuelva el número
 * de dígitos en vez de mostrarlo por pantalla ya que en el algoritmo de
 * Karatsuba es necesario saber el número de dígitos de un número.
 *
 */
 
int Digitos (int n, int &dig) {
	if (n < 10)	return (dig+1);
	else {
		dig++;
		return(Digitos(n/10, dig));
	}
}
 
/*
 * Recibimos el número de dígitos que queremos ver como últimos
 * y el número, claro
 * Devolvemos el módulo de dividir el número entre la potencia de 10
 * elevado al número de dígitos:
 * e.g. sacar los últimos 3 dígitos de 3454567:
 * 3454567 % power(10, 3) -> 3454567 % 1000 -> 567
 *
 */
int ultimos(int digitos, int &numero) {
	return numero % Power(10, digitos);
}
 
/*
 * Al igual que con los últimos, devolvemos los n primeros "digitos" de "numero".
 * para ello usamos algo simple: dividimos el número entre la potencia de 10 elevado
 * al número de dígitos que queremos sacar.
 *
 */
int primeros(int digitos, int &numero) {
	return numero/Power(10, digitos);
}
 
/*
 * Algoritmo de Karatsuba. Multiplicación rápida de enteros largos
 * @param: int &u -> pasamos por referencia uno de los números a multiplicar.
 * @param: int &v -> pasamos por referencia el segundo número.
 */
int multiplica (int &u, int &v) {
	int dig1=0, dig2=0;
	//División en trozos iguales de los números. Tenemos que dividir según
	//el mayor de ambos entre 2: 3457689 -> 345 y 7689
	//							 3455 -> 0 y 3455
	int numDigitos = max(Digitos(u, dig1), Digitos(v, dig2));
	//Caso base, cuando se puede hacer una multiplicación directa (1 cifra)
	//En teoría si se lograba beneficio con números de más de 300 bits, se podría
	//sustituir ese 1 por 300.
	if (numDigitos < = 1) return u*v;
	//Número de dígitos redondeados HACIA ARRIBA para sacar la división.
	//e.g -> 9 dígitos de máximo -> sacamos los 5 últimos y después los 4 primeros
	//NO podemos sacar los 4.5 mayores y los 4.5 menores
	numDigitos = (numDigitos / 2) + (numDigitos % 2);
	//Vamos calculando los diferentes w, x, y, z…
	int w = primeros(numDigitos, u);
	int x = ultimos(numDigitos, u);
	int y = primeros(numDigitos, v);
	int z = ultimos(numDigitos, v);
	//Operaciones intermedias
	int p=multiplica(w, y);
	int q=multiplica(x, z);
	int wMasx = w + x;
	int zMasy = z + y;
	//Volvemos a llamar al algoritmo hasta que (como se ve arriba en el if) lleguemos al
	//caso base de n=numDigitos=1. Llamada recursiva
	int r=multiplica(wMasx, zMasy);
	// Salida final, usamos la función Power implementada arriba
	return Power(10, 2*numDigitos)*p+Power(10, numDigitos)*(r-p-q)+q;
}
 
//Funcion aleatoria para sacar números aleatorios menores que el parámetro x
int MiRandom(int x)
{
	int Numero=0;
	Numero=(rand()%x);
	return Numero;
}
 
int main () {
	//Inicializamos la semilla apuntando al tiempo
	srand(time(NULL));
	int numero=0;
	//Menor que 46340 -> raiz(max_int)=raiz(2147483647)...
	//Obviamente podría funcionar con más de 46340, pero podría producirse overflow.
	//Sólo ocurriría en el caso de que la semilla hiciera dos 46341 -> bum!!
	// Se podría poner hasta semilla 2147483647 si se tuviera la suerte que el random
	// fuera 1 y 2147483647
	//Además es que hemos limitado a "int", si hubiéramos puesto un valor más grande, como
	//unsigned long long int, tendríamos valores perfectos y muy grandes
	cout < < "Número máximo a multiplicar (menor que 46341, leer código fuente) :";
	cin >> numero;
	//Creamos dos enteros aleatorios máximo "numero"
	int num1 = MiRandom(numero);
	int num2 = MiRandom(numero);
	//Les mostramos
	cout < < "\nnum1=" << num1;
	cout << "\nnum2=" << num2;
	//Les multiplicamos!
	cout << "\nEl resultado del producto es: " << multiplica(num1, num2);
	return EXIT_SUCCESS;
}

History