martes, 23 de agosto de 2016

VBA: Multiplicación por duplicación - la multiplicación rusa.

Quizá este método de multiplicación rusa (o por duplicación) te suene a 'chino'...
pero es tan antiguo como la cultura de los faraones.
Es un método de multiplicación basado en la suma y división por dos.
Puedes echar un vistazo en Wikipedia.

Pero se resume básicamente en:
1-Escribir los números (A y B) que se desea multiplicar en la parte superior de sendas columnas.
2-Dividir A entre 2, sucesivamente, ignorando el resto, hasta llegar a la unidad. Escribir los resultados en la columna A.
3-Multiplicar B por 2 tantas veces como veces se ha dividido A entre 2. Escribir los resultados sucesivos en la columna B.
4-Sumar todos los números de la columna B que estén al lado de un número impar de la columna A. Éste es el resultado.


Veamos un ejemplo del desarrollo en Excel.
Tenemos dos valores a multiplicar en C2:=13 y en D2:=313
En el primer rango C5:C14 hemos añadido el valor de C2 (=13) y los siguientes (C6 y siguientes) la fórmula:
=ENTERO(C5/2)
con la que conseguimos los valores enteros necesarios.


En la columna de al lado, rango D5:D14, completamos con:
En D5 recuperamos el valor de D2 (=313), y en D6 y siguientes añadimos la fórmula:
=SI(C6>0;D5*2;0)
obteniendo el doble del valor anterior...


Finalmente en el rango E5:E14 incorporamos el condicional:
=SI(ES.IMPAR(C5);D5;0)
que nos retornará los importes necesarios a sumar, sólo para los valores impares del primer rango(C5:C14).
Acabamos sumando en E15 los importes del rango superior:
=SUMA(E5:E14)

VBA: Multiplicación por duplicación - la multiplicación rusa.



Obviamente, por suerte, no tendremos que hacer estas operaciones tan laboriosas para conseguir nuestro producto... pero sirve de introducción para el ejercicio siguiente, que consiste en replicar el método en VBA para Excel.
Construiremos una UDF, un procedimiento Function, como el que sigue:

Function MultRusa(pdto1 As Integer, pdto2 As Double) As Double
'definimos dos matrices
Dim Valores1() As Variant
Dim Valores2() As Variant
'calculamos el número de lineas a trabajar
N = 0
Do
    'tantas lineas necesarias
    'hasta que superemso el valor del primer valor a multiplicar
    Eltos = 2 ^ N
    N = N + 1
Loop Until Eltos > pdto1

'redefinimos la dimensión de nuestras matrices
'ajustadas al númer de líneas necesarias
ReDim Valores1(1 To N) As Variant
ReDim Valores2(1 To N) As Variant

'asignamos valores a las matrices
Valores1(1) = Int(pdto1)    'el primer rango será siempre entero
Valores2(1) = pdto2
'completamos las matrices con el siguiente bucle
N = 2
Do
    'a partir del valor anterior calculamos el siguiente dividiendo por dos
    Valores1(N) = Int(Valores1(N - 1) / 2)
    'a partir del valor anterior calculamos el siguiente multiplicando por dos
    Valores2(N) = Valores2(N - 1) * 2
    N = N + 1
Loop Until Valores1(N - 1) = 1

'recorremos las matrices
Dim dato As Variant
For Each dato In Valores1
    x = x + 1
    If (dato Mod 2) <> 0 Then
        'acumulamos los importes de la segunda matriz
        'solo cuando el valor de la primera sea impar
        Suma = Suma + Valores2(x)
    End If
Next dato

'devolvemos el sumando a la celda
MultRusa = Suma
End Function



El resultado, claro está, es el esperado:

VBA: Multiplicación por duplicación - la multiplicación rusa.



Lo interesante de este post, me atrevo a decir, es el uso de las Arrays y de los loops tipo DO...LOOP y FOR EACH..NEXT, empleados para la construcción de los rangos necesarios (divididos y multiplicados por dos), así como para obtener el número de líneas en esos rangos....

No hay comentarios:

Publicar un comentario en la entrada