+template < typename N, typename E >
+number< N, E >& number< N, E >::operator*= (const number< N, E >& n)
+{
+ number < N, E > r_op = n;
+ normalize_length(n);
+ n.normalize_length(*this);
+ *this = divide_n_conquer(*this, n);
+ return *this;
+}
+
+template < typename N, typename E >
+number< N, E > operator* (const number< N, E >& n1, const number< N, E >& n2)
+{
+ number< N, E > tmp = n1;
+ tmp *= n2;
+ return tmp;
+}
+
+template < typename N, typename E >
+number< N, E >& number< N, E >::normalize_length(const number< N, E >& n)
+{
+ // si son de distinto tamaño tengo que agregar ceros a la izquierda al
+ // menor para división y conquista
+ while (chunk.size() < n.chunk.size())
+ {
+ chunk.push_back(0);
+ }
+
+ // si no tiene cantidad par de números le agrego un atomic_type 0 a la
+ // izquierda para no tener que contemplar splits de chunks impares
+ if ((chunk.size() % 2) != 0)
+ {
+ chunk.push_back(0);
+ }
+}
+
+template < typename N, typename E >
+std::pair< number< N, E >, number< N, E > > number< N, E >::split() const
+{
+ typedef number< N, E > num_type;
+ typename num_type::size_type full_size = chunk.size();
+ typename num_type::size_type halves_size = full_size / 2;
+ typename num_type::size_type i = 0;
+
+ // vacío las mitades
+ std::pair< num_type, num_type > par;
+
+ // la primera mitad va al pedazo inferior
+ for (i = 0; i < halves_size; i++)
+ {
+ par.first.chunk.push_back(chunk[i]);
+ }
+
+ // la segunda mitad (si full_size es impar es 1 más que la primera
+ // mitad) va al pedazo superior
+ for ( ; i < full_size; i++)
+ {
+ par.second.chunk.push_back(chunk[i]);
+ }
+ return par;
+}
+
+// es el algoritmo de división y conquista, que se llama recursivamente
+template < typename N, typename E >
+number < N, E > karatsuba(number< N, E > u, number< N, E > v)
+{
+ typedef number< N, E > num_type;
+
+ // tomo el chunk size de u (el de v DEBE ser el mismo)
+ typename num_type::size_type chunk_size = u.chunk.size();
+
+ if (chunk_size == 1)
+ {
+ // condición de corte. Ver que por más que tenga 1 único
+ // elemento puede "rebalsar" la capacidad del atomic_type,
+ // como ser multiplicando 0xff * 0xff usando bytes!!!
+ return u.chunk[0] * v.chunk[0];
+ }
+
+ std::pair< num_type, num_type > u12 = u.split();
+ std::pair< num_type, num_type > v12 = v.split();
+
+ // Los nombres M, D y H los puso Rosita en clase, cambiar si se les
+ // ocurren algunos mejores!
+ // m = u1*v1
+ // d = u2*v2
+ // h = (u1+v1)*(u2+v2) = u1*u2+u1*v2+u2*v1+u2*v2
+ num_type m = karastuba(u12.first, v12.first);
+ num_type d = karastuba(u12.second, v12.second);
+ num_type h = karastuba(u12.first + v12.first,
+ u12.second + v12.second);
+
+ // H-D-M = u1*u2+u1*v2+u2*v1+u2*v2 - u2*v2 - u1*v1 = u1*v2+u2*v1
+ // u1*v1 << base^N + u1*v2+u2*v1 << base^N/2 + u2*v2
+ return (m << chunk_size) + ((h - d - m) << chunk_size / 2) + h;
+
+}
+