/* 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;
}