el Guille, la Web del Visual Basic, C#, .NET y más...


 

Índice de la sección dedicada a .NET (en el Guille) Cómo... en .NET

Operar con números grandes

Cómo realizar operaciones con números enteros demasiados grandes que ni el propio .NET puede realizar

Código para Visual Basic.NET (VB.NET)

Código para Visual Basic 6.0 (o anterior a .NET)

Código para C Sharp (C#)


Publicado el 10/Ago/2004
Actualizado el 12/Ago/2004
Autor: Guillermo 'guille' Som

Revisiones 01. y 0.2 (11/Ago)

Contenido:

 

 Introducción

El otro día estaba intentando hacer operaciones con números demasiado grandes (de por ejemplo 97 cifras cada uno) pero resulta que si bien el .NET puede realizarlas, al final acaba haciéndolo con valores de tipo Double y usando notación científica, con lo que no me servía ya que necesitaba que todos los dígitos fuesen válidos y estuviesen a la vista... al final, acabé maldiciendo al .NET y la falta de previsión de ese tipo de operaciones.

Buscando por la Web me encontré con programas especializados (y en la mayoría de los casos, con unos precios descomunales), lo único válido que encontré, además del amzi! Prolog, fue la aplicación "bc GNU" (bc - An arbitrary precision calculator language) una aplicación que permite realizar ciertas operaciones que no nos limitan el número de dígitos, además de que también podemos indicar si queremos o no usar decimales, este lenguaje "calculador" tiene ciertas instrucciones como la de realizar bucles for o bucles while de forma más o menos fácil, al menos para mi, que eso de Prolog me resultaba algo "enrevesado" para hacer ciertas cosas "simples".

La cuestión es que para los cálculos estoy usando bc, pero me dije que sería interesante poder realizar ese tipo de cálculos en .NET (e incluso en VB6).

Y aquí está lo que por ahora he hecho con esto de los números enteros de cualquier cantidad de dígitos:
-Sumar dos números (o varios) enteros de cualquier cantidad de dígitos,
-Multiplicar dos (o varios) números
-Realizar exponenciaciones (elevar un número a cualquier otro)
-Restar dos números (o varios)

Por ahora no me he puesto a usar números con fracciones decimales ni a realizar la división, para eso necesitaré la ayuda de algún "matemático" que me explique cómo hacer ese tipo de operaciones trabajando individualmente con los dígitos que componen el número... ya que de eso se trata: de ir operando con cada uno de los dígitos de forma individual... tal y como lo hacemos manualmente.

En fin... si alguien se anima... pues podríamos hacer algo que realmente sea útil...

Mi idea será, en principio, crear un tipo de datos (una estructura) en C# en la que poder crear sobrecargas de operadores y conversiones a otros tipos de datos, cuando la versión 2005 de VB esté más avanzada, convertiré ese código a VB ya que en la versión 2005 se podrán crear sobrecargas de operadores y demás cosillas que actualmente sólo se pueden hacer con C#.

Aquí te pongo el código para VB .NET 2003 (será fácil convertirlo a la versión 2002, ya que realmente sólo hago uso de la declaración de variables en los bucles).

También pondré el código de C# y el código para VB6, así que... sigue comprobando esta página ya que seguramente habrá novedades pronto... al menos eso espero.

 

 Para probar el código (y los resultados)

Para que puedas probar desde la línea de comandos, el proyecto (de consola) recibe argumentos de la línea de comandos, esos argumentos serán los dos números con los que operar y la operación a realizar.
Es decir, se indicarán los números con los que se deben operar y después la operación a realizar (a esto se le llama notación Polaca, por si te interesa saberlo).
Las operaciones podrán ser: * multiplicar, + sumar, - restar y ** elevar a una potencia, por ejemplo:
multStr 1234567890123456789012345 123456789 *
multStr 125 500 **

Por supuesto, para comprobar que todas estas operaciones devuelven un resultado correcto tendrás que usar algún programa que sea capaz de realizarlas!!!
En el caso de 125 elevado a 500... ¡¡¡el número tendrá 1049 dígitos!!!

Para comprobar los resultados, también puedes usar GNU bc, (desde la lista de referencias puedes bajar el ejecutable, la documentación y el código), aunque para usarla debes crear un fichero que realice las operaciones que quieres realizar y después llamar a bc.exe, por ejemplo, puedes crear un fichero llamado "pruebas.bc" con el siguiente contenido:

res = 1234567890123456789012345 * 123456789
print res, "\n\n"

res = 125 ^ 500
print "125 ^ 500 = \n", res, "\n"

quit

Y después usarla de esta forma:
bc pruebas.bc

 

 Las funciones incluidas (los tipos de operaciones soportadas)

Aunque en este primer intento, (que hice anoche), todo el código está en el mismo módulo, al menos te indicaré las funciones que tiene y para que sirven, así, si quieres modificarlo, sepas de forma más fácil cómo funciona.

En algunas funciones se permiten dos parámetros o un array de varios parámetros, por ejemplo, si quieres multiplicar dos números puedes llamar a la función Mult2(n1, n2) indicando los dos números a multiplicar, pero si quieres realizar varias operaciones de multiplicación, puedes llamar a Mult2(n1, n2, n3, ... nN).
cada función se indicará seguida de /2 si recibe 2 parámetros y/o de /N si recibe N parámetros. Esta es una notación que usa en Prolog para indicar el número de parámetros que recibe cada función, y como me gusta...
Todas las funciones devuelven una cadena con el resultado.

  • Mult2 (Mult2/2 y Mult2/N)
    Multiplica dos (o N números).
  • PotN (PotN/2)
    Eleva el primer número a la potencia indicada (realmente multiplica N veces el primer número indicado)
  • Resta2 (Resta2/2 y Resta2/N)
    Resta 2 números o N números
  • Suma2 (suma2/2 y Suma2/N)
    Suma 2 o más números
  • Div2 (Div2/2) (rev 0.1)
    Divide dos números
  • Sobrecargado los operadores *, /, +, -, >, <, ==, != (rev 0.2)
    Esto sólo para la versión de C#
  • Sobrecargado los operadores ++, -- (rev 0.3, por publicar)
    Esto sólo para la versión de C#

Internamente se usan las siguientes funciones y variables:

  • ad() un array con cada uno de los números con los que hay que operar
    Mult2 calcula cada una de las líneas y las guarda en el array ad() que posteriormente se sumará para conseguir el resultado.
  • swap cambia el contenido de los dos parámetros indicados, los parámetros se pasarán por referencia. Este método lo uso para poner primero el número más largo y después el más corto.
  • sumarFilas, suma el contenido del array ad() (cada uno de los elementos) y devuelve el resultado.
  • restar2Filas, resta los dos primeros elementos del array ad() y devuelve el resultado.

 

Nos vemos.
Guillermo


 Referencias


 Colaborar en este proyecto

Si quieres, puedes participar en este proyecto, creo que puede ser interesante.
La idea es conseguir hacer cálculos con números bastantes grandes (de muchos dígitos) y por supuesto hacerlo lo más rápido posible, ya que, por ejemplo, el código de elevar a potencias, es relativamente lento...

Las cosas que tengo anotadas por hacer:
(revisa siempre la última actualización para saber que es lo que hay pendiente de hacer)

  • Trabajar con decimales (hecho rev 0.1)
  • Dividir números (hecho rev 0.1)
  • Calcular la raíz cuadrada
  • Trabajar con números negativos
  • ...lo que se me ocurra o lo que propongas...

Así que si te animas... me mandas un mensaje a: mensaje @ elguille.info con el asunto "Participar en numeros grandes" y ya hablamos.

Gracias.

Nota del 17/Ene/2019:
Esto es de hace 15 años, así que... si después de verlo nuevamente quieres colaborar... pues... no sé si lo volveré a retomar, de todas formas ya hice en su día cosas nuevas (usando DLL de F#) y... bueno, lo publiqué en ProgramarPorProgramar.org y... actualmente ese sitio ya no va... (pero lo quiero reactivar ya que el dominio lo tengo pagado ;-) )
Pero ya te digo... si me escribes y no te respondo, pues... que no te lo tomes a mal.
Gracias.


Código para Visual Basic.NET (VB.NET)El código para VB .NET

 

'------------------------------------------------------------------------------
' Multiplicar números usando cadenas de caracteres                    (10/Ago/04)
' Realizar operaciones con números enteros de cualquier longitud
' Operaciones soportadas:
'    Multiplicación, Potencias, Suma y Resta
'
' ©Guillermo 'guille' Som, 2004
'------------------------------------------------------------------------------
Option Explicit On 
Option Strict On

Imports vb = Microsoft.VisualBasic
Imports System

Module MultStr
    Dim ad() As String
    '
    Sub Main(ByVal args() As String)
        '
        'Console.WriteLine("125 ^ 9 = {0}", 125 ^ 9)
        'Console.WriteLine()
        '
        Dim num1 As String = "123"
        Dim num2 As String = "123"
        Dim op As String = "*"
        If args.Length > 1 Then
            num1 = args(0)
            num2 = args(1)
        End If
        If num2.Length > num1.Length Then
            swap(num1, num2)
        End If
        '
        If args.Length = 3 Then
            op = args(2)
        End If
        '
        Select Case op
            Case "+"
                Console.WriteLine(Suma2(num1, num2))
            Case "-"
                Console.WriteLine(Resta2(num1, num2))
            Case "**"
                Console.WriteLine(PotN(num1, num2))
            Case "*", "x"
                Console.WriteLine(Mult2(num1, num2))
                '
                ' Para mostrar todas las cifras que intervienen
                ' en las operaciones, comenta esto si sólo quieres el resultado
                Dim res As String = Mult2(num1, num2)
                Dim k As Integer = res.Length
                Console.WriteLine("  {0," & k.ToString & "}", num1)
                Console.WriteLine("x {0," & k.ToString & "}", num2)
                Console.WriteLine(New String("-"c, k + 2))
                For i As Integer = 0 To ad.Length - 1
                    Console.WriteLine("  {0," & k.ToString & "}", ad(i))
                Next
                Console.WriteLine(New String("-"c, k + 2))
                Console.WriteLine("  {0," & k.ToString & "}", res)
        End Select
    End Sub
    '
    '
    Public Function PotN(ByVal num1 As String, ByVal elevado As String) As String
        Dim i As Integer = CInt(elevado) - 1
        Dim p(i) As String
        For k As Integer = 0 To i
            p(k) = num1
        Next
        Return Mult2(p)
    End Function
    '
    Public Function Mult2(ByVal ParamArray nums() As String) As String
        Dim total As String = nums(0)
        For i As Integer = 1 To nums.Length - 1
            Dim n1 As String = nums(i)
            total = Mult2(total, n1)
        Next
        '
        Return total
    End Function
    '
    Public Function Mult2(ByVal num1 As String, ByVal num2 As String) As String
        '
        ' Poner el más largo como primer número
        If num2.Length > num1.Length Then
            swap(num1, num2)
        End If
        '
        ' El número de operaciones necesarias
        ' será la cantidad de cifras del más pequeño
        ReDim ad(num2.Length - 1)
        Dim n As Integer = -1
        Dim resto As String = "0"
        Dim res As String = ""
        '
        ' Multiplicar formando filas con los resultados (al estilo manual)
        For i As Integer = num2.Length - 1 To 0 Step -1
            n += 1
            ad(n) = ""
            ' Añadir espacios a la derecha según la cifra (fila) que se procese
            For k As Integer = 1 To n
                ad(n) &= " "
            Next
            Dim c1 As String = num2.Substring(i, 1)
            ' Para simplificar las cosas
            ' se comprueba si se multiplicará por ceo o por uno
            ' de forma que no sea necesario hacer estas operaciones
            If c1 = "0" Then
                ad(n) = New String("0"c, num1.Length) & ad(n)
            ElseIf c1 = "1" Then
                ad(n) = num1 & ad(n)
            Else
                For j As Integer = num1.Length - 1 To 0 Step -1
                    Dim c2 As String = num1.Substring(j, 1)
                    res = (CInt("0" & c1) * CInt("0" & c2) + CInt(resto)).ToString
                    ad(n) = vb.Right(res, 1) & ad(n)
                    If res.Length - 1 < 1 Then
                        resto = "0"
                    Else
                        resto = res.Substring(0, res.Length - 1)
                    End If
                Next
                If resto <> "0" Then
                    ad(n) = resto & ad(n)
                    resto = "0"
                End If
            End If
        Next
        '
        Return sumarFilas()
    End Function
    '
    Public Function Suma2(ByVal ParamArray nums() As String) As String
        '
        ReDim ad(nums.Length - 1)
        For i As Integer = 0 To nums.Length - 1
            ad(i) = nums(i)
        Next
        '
        Return sumarFilas()
    End Function
    '
    Public Function Suma2(ByVal num1 As String, ByVal num2 As String) As String
        ReDim ad(1)
        ad(0) = num1
        ad(1) = num2
        '
        Return sumarFilas()
    End Function
    '
    Public Function Resta2(ByVal ParamArray nums() As String) As String
        Dim total As String = nums(0)
        For i As Integer = 1 To nums.Length - 1
            Dim n1 As String = nums(i)
            total = Resta2(total, n1)
        Next
        '
        Return total
    End Function
    '
    Public Function Resta2(ByVal num1 As String, ByVal num2 As String) As String
        ReDim ad(1)
        ad(0) = num1
        ad(1) = num2
        '
        Return restar2Filas()
    End Function
    '
    Private Function sumarFilas() As String
        Dim m As Integer = 0
        Dim n As Integer = ad.Length - 1
        '
        ' m será el número de mayor longitud
        For k As Integer = 0 To n
            If ad(k).Length > m Then m = ad(k).Length
        Next
        '
        ' sumar las filas obtenidas
        Dim resto As String = "0"
        Dim total As String = ""
        Dim res As String = ""
        '
        For k As Integer = 0 To n
            ad(k) = vb.Right(New String(" "c, m) & ad(k), m)
        Next
        For k As Integer = m - 1 To 0 Step -1
            res = resto
            For i As Integer = 0 To n
                res = (CInt(res) + CInt("0" & ad(i).Substring(k, 1))).ToString
            Next
            total = vb.Right(res, 1) & total
            If res.Length - 1 < 1 Then
                resto = "0"
            Else
                resto = res.Substring(0, res.Length - 1)
            End If
        Next
        If resto <> "0" Then
            total = resto & total
        End If
        '
        Return total
    End Function
    '
    Private Function restar2Filas() As String
        Dim m As Integer = 0
        Dim n As Integer = ad.Length - 1
        '
        For k As Integer = 0 To n
            If ad(k).Length > m Then m = ad(k).Length
        Next
        '
        ' restar las filas obtenidas
        Dim resto As String = "0"
        Dim total As String = ""
        Dim res As String = ""
        '
        For k As Integer = 0 To n
            ad(k) = vb.Right(New String(" "c, m) & ad(k), m)
        Next
        For k As Integer = m - 1 To 0 Step -1
            res = (CInt("0" & ad(0).Substring(k, 1)) - (CInt("0" & ad(1).Substring(k, 1)) + CInt(resto))).ToString
            If CInt(res) < 0 Then
                res = (CInt(res) + 10).ToString
            End If
            total = vb.Right(res, 1) & total
            If res.Length - 1 < 1 Then
                resto = "0"
            Else
                resto = res.Substring(0, res.Length - 1)
            End If
        Next
        If resto <> "0" Then
            total = resto & total
        End If
        '
        Return total
    End Function
    '
    Private Sub swap(ByRef n1 As String, ByRef n2 As String)
        Dim t As String = n1
        n1 = n2
        n2 = t
    End Sub
End Module

 


Código para C Sharp (C#)El código para C#

 

//-----------------------------------------------------------------------------
// Multiplicar números usando cadenas de caracteres                    (10/Ago/04)
// Realizar operaciones con números enteros de cualquier longitud
//
// Operaciones soportadas:
//    Multiplicación, Potencias, Suma y Resta
//
// ©Guillermo 'guille' Som, 2004
//-----------------------------------------------------------------------------
 
using System;
 
class MultStr{
    private static string[] ad;
    //
    [STAThread]
    static void Main(string[] args) {
        //
        string num1 = "123";
        string num2 = "123";
        string op = "*";
        if( args.Length > 1 ){
            num1 = args[0];
            num2 = args[1];
        }
        if( num2.Length > num1.Length ){
            swap(ref num1, ref num2);
        }
        //
        if( args.Length == 3 ){
            op = args[2];
        }
        //
        switch(op){
            case "+":
                Console.WriteLine(Suma2(num1, num2));
                break;
            case "-":
                Console.WriteLine(Resta2(num1, num2));
                break;
            case "**":
                Console.WriteLine(PotN(num1, num2));
                break;
            case "*":
            case "x":
                Console.WriteLine(Mult2(num1, num2));
                //
                // Para mostrar todas las cifras que intervienen
                string res = Mult2(num1, num2);
                int k = res.Length;
                Console.WriteLine("  {0," + k.ToString() + "}", num1);
                Console.WriteLine("x {0," + k.ToString() + "}", num2);
                Console.WriteLine(new string('-', k + 2));
                for(int i= 0; i<= ad.Length - 1; i++){
                    Console.WriteLine("  {0," + k.ToString() + "}", ad[i]);
                }
                Console.WriteLine(new string('-', k + 2));
                Console.WriteLine("  {0," + k.ToString() + "}", res);
                break; 
        }
        //
        Console.ReadLine(); 
    }  
    //
    //
    public static string PotN(string num1, string elevado) {
        int i = Convert.ToInt32(elevado) - 1;
        string[] p = new string[(i + 1)];
        for(int k= 0; k<= i; k++){
            p[k] = num1;
        }
        return Mult2(p);
    }  
    //
    public static string Mult2( params string[] nums) {
        string total = nums[0];
        for(int i= 1; i<= nums.Length - 1; i++){
            string n1 = nums[i];
            total = Mult2(total, n1);
        }
        //
        return total;
    }  
    //
    public static string Mult2(string num1, string num2) {
        //
        // Poner el más largo como primer número
        if( num2.Length > num1.Length ){
            swap(ref num1, ref num2);
        }
        //
        // El número de operaciones necesarias
        // será la cantidad de cifras del más pequeño
        ad = new string[num2.Length];
        int n = -1;
        string resto = "0";
        string res = "";
        //
        // Multiplicar formando filas con los resultados (al estilo manual)
        for(int i= num2.Length - 1; i>= 0; i--){
            n += 1;
            ad[n] = "";
            // Añadir espacios a la derecha según la cifra (fila) que se procese
            for(int k= 1; k<= n; k++){
                ad[n] += " ";
            }
            string c1 = num2.Substring(i, 1);
            // Para simplificar las cosas
            // se comprueba si se multiplicará por ceo o por uno
            // de forma que no sea necesario hacer estas operaciones
            if( c1 == "0" ){
                ad[n] = new string('0', num1.Length) + ad[n];
            }else if( c1 == "1" ){
                ad[n] = num1 + ad[n];
            }else{
                for(int j= num1.Length - 1; j>= 0; j--){
                    string c2 = num1.Substring(j, 1);
                    res = (Convert.ToInt32("0" + c1) * Convert.ToInt32("0" + c2) + Convert.ToInt32(resto)).ToString();
                    ad[n] = res.Substring(res.Length - 1, 1) + ad[n];
                    if( res.Length - 1 < 1 ){
                        resto = "0";
                    }else{
                        resto = res.Substring(0, res.Length - 1);
                    }
                }
                if( resto != "0" ){
                    ad[n] = resto + ad[n];
                    resto = "0";
                }
            }
        }
        //
        return sumarFilas();
    }  
    //
    public static string Suma2( params string[] nums) {
        //
        ad = new string[nums.Length];
        for(int i= 0; i< nums.Length; i++){
            ad[i] = nums[i];
        }
        //
        return sumarFilas();
    }  
    //
    public static string Suma2(string num1, string num2) {
        ad = new string[2];
        ad[0] = num1;
        ad[1] = num2;
        //
        return sumarFilas();
    }  
    //
    public static string Resta2( params string[] nums) {
        string total = nums[0];
        for(int i= 1; i< nums.Length; i++){
            string n1 = nums[i];
            total = Resta2(total, n1);
        }
        //
        return total;
    }  
    //
    public static string Resta2(string num1, string num2) {
        ad = new string[2];
        ad[0] = num1;
        ad[1] = num2;
        //
        return restar2Filas();
    }  
    //
    private static string sumarFilas() {
        int m = 0;
        int n = ad.Length - 1;
        //
        // m será el número de mayor longitud
        for(int k= 0; k<= n; k++){
            if( ad[k].Length > m ) m = ad[k].Length;
        }
        //
        // sumar las filas obtenidas
        string resto = "0";
        string total = "";
        string res = "";
        //
        for(int k= 0; k<= n; k++){
            ad[k] = (new string(' ', m) + ad[k]).Substring(ad[k].Length, m);
        }
        for(int k= m - 1; k>= 0; k--){
            res = resto;
            for(int i= 0; i<= n; i++){
                res = (Convert.ToInt32(res) + Convert.ToInt32("0" + ad[i].Substring(k, 1))).ToString();
            }
            total = res.Substring(res.Length - 1, 1) + total;
            if( res.Length - 1 < 1 ){
                resto = "0";
            }else{
                resto = res.Substring(0, res.Length - 1);
            }
        }
        if( resto != "0" ){
            total = resto + total;
        }
        //
        return total;
    }  
    //
    private static string restar2Filas() {
        int m = 0;
        int n = ad.Length - 1;
        //
        for(int k= 0; k<= n; k++){
            if( ad[k].Length > m ) m = ad[k].Length;
        }
        //
        // restar las filas obtenidas
        string resto = "0";
        string total = "";
        string res = "";
        //
        for(int k= 0; k<= n; k++){
            ad[k] = (new string(' ', m) + ad[k]).Substring(ad[k].Length, m);
        }
        for(int k= m - 1; k>= 0; k--){
            res = (Convert.ToInt32("0" + ad[0].Substring(k, 1)) - (Convert.ToInt32("0" + ad[1].Substring(k, 1)) + Convert.ToInt32(resto))).ToString();
            if( Convert.ToInt32(res) < 0 ){
                res = (Convert.ToInt32(res) + 10).ToString();
            }
            total = res.Substring(res.Length - 1, 1) + total;
            if( res.Length - 1 < 1 ){
                resto = "0";
            }else{
                resto = res.Substring(0, res.Length - 1);
            }
        }
        if( resto != "0" ){
            total = resto + total;
        }
        //
        return total;
    }  
    //
    private static void swap(ref string n1, ref string n2) {
        string t = n1;
        n1 = n2;
        n2 = t;
    }  
}

 


El código para Visual Basic 6.0 (o anteriores a VB .NET)

El formulario de prueba (y una captura en tiempo de ejecución)


El formulario en tiempo de ejecución.

 

'------------------------------------------------------------------------------
' Realizar operaciones con números grandes usando cadenas           (10/Ago/04)
' Formulario de prueba para Visual Basic 6.0
'
' Realizar operaciones con números enteros de cualquier longitud
' Operaciones soportadas:
'   Multiplicación, Potencia, Suma y Resta
'
' ©Guillermo 'guille' Som, 2004
'------------------------------------------------------------------------------
Option Explicit

Private Sub cmdCalcular_Click()
    Select Case Left$(cboOp.Text, 1)
    Case "+"
        txtRes.Text = Suma2(txtNum1.Text, txtNum2.Text)
    Case "-"
        txtRes.Text = Resta2(txtNum1.Text, txtNum2.Text)
    Case "*"
        txtRes.Text = Mult2(txtNum1.Text, txtNum2.Text)
    Case "^"
        txtRes.Text = PotN(txtNum1.Text, txtNum2.Text)
    End Select
End Sub

Private Sub Form_Load()
    With cboOp
        .Clear
        .AddItem ("+ - Sumar")
        .AddItem ("- - Restar")
        .AddItem ("* - Multiplicar")
        .AddItem ("^ - Elevar a potencia")
        .ListIndex = 2
    End With
    txtNum1.Text = "1234567890123456789012345"
    txtNum2.Text = "12345678901234567890"
    txtRes.Text = ""
End Sub

Private Sub Form_Resize()
    If WindowState <> vbMinimized Then
        txtNum1.Width = ScaleWidth - txtNum1.Left - 240
        txtNum2.Width = txtNum1.Width
        cmdCalcular.Left = ScaleWidth - cmdCalcular.Width - 240
        txtRes.Width = txtNum1.Width
        txtRes.Height = ScaleHeight - txtRes.Top - 240
    End If
End Sub

 

El código del módulo con las funciones

'------------------------------------------------------------------------------
' Módulo con las funciones para realizar los cálculos               (10/Ago/04)
' Versión para Visual Basic 6.0
'
' Realizar operaciones con números enteros de cualquier longitud
' Operaciones soportadas:
'   Multiplicación, Potencia, Suma y Resta
'
' ©Guillermo 'guille' Som, 2004
'------------------------------------------------------------------------------
Option Explicit

Private ad() As String

Public Function PotN(ByVal num1 As String, ByVal elevado As String) As String
    Dim i As Long
    Dim p() As String
    Dim k As Long
    '
    i = CLng(elevado) - 1
    ReDim p(i)
    For k = 0 To i
        p(k) = num1
    Next
    PotN = Mult2N(p)
End Function
'
Public Function Mult2N(ParamArray nums() As Variant) As String
    Dim total As String
    Dim n1 As String
    Dim i As Long
    '
    If IsArray(nums(0)) Then
        total = nums(0)(0)
        For i = 1 To UBound(nums(0))
            n1 = nums(0)(i)
            total = Mult2(total, n1)
        Next
    Else
        total = nums(0)
        For i = 1 To UBound(nums)
            n1 = nums(i)
            total = Mult2(total, n1)
        Next
    End If
    '
    Mult2N = total
End Function
'
Public Function Mult2(ByVal num1 As String, ByVal num2 As String) As String
    '
    ' Poner el más largo como primer número
    If Len(num2) > Len(num1) Then
        Call swap(num1, num2)
    End If
    '
    ' El número de operaciones necesarias
    ' será la cantidad de cifras del más pequeño
    ReDim ad(Len(num2) - 1)
    Dim n As Long
    n = -1
    Dim resto As String
    resto = "0"
    Dim res As String
    '
    ' Multiplicar formando filas con los resultados (al estilo manual)
    Dim i As Long
    For i = Len(num2) To 1 Step -1
        n = n + 1
        ad(n) = ""
        ' Añadir espacios a la derecha según la cifra (fila) que se procese
        Dim k As Long
        For k = 1 To n
            ad(n) = ad(n) & " "
        Next
        Dim c1 As String
        c1 = Mid$(num2, i, 1)
        ' Para simplificar las cosas
        ' se comprueba si se multiplicará por ceo o por uno
        ' de forma que no sea necesario hacer estas operaciones
        If c1 = "0" Then
            ad(n) = String$(Len(num1), "0") & ad(n)
        ElseIf c1 = "1" Then
            ad(n) = num1 & ad(n)
        Else
            Dim j As Long
            For j = Len(num1) To 1 Step -1
                Dim c2 As String
                c2 = Mid$(num1, j, 1)
                res = CStr(CLng("0" & c1) * CLng("0" & c2) + CLng(resto))
                ad(n) = Right$(res, 1) & ad(n)
                If Len(res) - 1 < 1 Then
                    resto = "0"
                Else
                    resto = Left$(res, Len(res) - 1)
                End If
            Next
            If resto <> "0" Then
                ad(n) = resto & ad(n)
                resto = "0"
            End If
        End If
    Next
    '
    Mult2 = sumarFilas()
End Function
'
Public Function Suma2N(ParamArray nums() As Variant) As String
    Dim i As Long
    '
    If IsArray(nums(0)) Then
        ReDim ad(UBound(nums(0)))
        For i = 0 To UBound(nums(0))
            ad(i) = nums(0)(i)
        Next
    Else
        ReDim ad(UBound(nums))
        For i = 0 To UBound(nums)
            ad(i) = nums(i)
        Next
    End If
    '
    Suma2N = sumarFilas()
End Function
'
Public Function Suma2(ByVal num1 As String, ByVal num2 As String) As String
    ReDim ad(1)
    ad(0) = num1
    ad(1) = num2
    '
    Suma2 = sumarFilas()
End Function
'
Public Function Resta2N(ParamArray nums() As Variant) As String
    Dim total As String
    Dim i As Long
    Dim n1 As String
    '
    If IsArray(nums(0)) Then
        total = nums(0)(0)
        For i = 1 To UBound(nums(0))
            n1 = nums(0)(i)
            total = Resta2(total, n1)
        Next
    Else
        total = nums(0)
        For i = 1 To UBound(nums)
            
            n1 = nums(i)
            total = Resta2(total, n1)
        Next
    End If
    '
    Resta2N = total
End Function
'
Public Function Resta2(ByVal num1 As String, ByVal num2 As String) As String
    ReDim ad(1)
    ad(0) = num1
    ad(1) = num2
    '
    Resta2 = restar2Filas()
End Function
'
Private Function sumarFilas() As String
    Dim i As Long
    Dim k As Long
    Dim m As Long
    Dim n As Long
    n = UBound(ad)
    '
    ' m será el número de mayor longitud
    For k = 0 To n
        If Len(ad(k)) > m Then m = Len(ad(k))
    Next
    '
    ' sumar las filas obtenidas
    Dim resto As String
    resto = "0"
    Dim total As String
    Dim res As String
    '
    For k = 0 To n
        ad(k) = Right$(String$(m, " ") & ad(k), m)
    Next
    For k = m To 1 Step -1
        res = resto
        For i = 0 To n
            res = CStr(CLng(res) + CLng("0" & Mid$(ad(i), k, 1)))
        Next
        total = Right$(res, 1) & total
        If Len(res) - 1 < 1 Then
            resto = "0"
        Else
            resto = Left$(res, Len(res) - 1)
        End If
    Next
    If resto <> "0" Then
        total = resto & total
    End If
    '
    sumarFilas = total
End Function
'
Private Function restar2Filas() As String
    Dim k As Long
    Dim m As Long
    Dim n As Long
    n = UBound(ad)
    '
    For k = 0 To n
        If Len(ad(k)) > m Then m = Len(ad(k))
    Next
    '
    ' restar las filas obtenidas
    Dim resto As String
    resto = "0"
    Dim total As String
    Dim res As String
    '
    For k = 0 To n
        ad(k) = Right$(String$(m, " ") & ad(k), m)
    Next
    For k = m To 1 Step -1
        res = CStr(CLng("0" & Mid$(ad(0), k, 1)) - (CLng("0" & Mid$(ad(1), k, 1)) + CLng(resto)))
        If CLng(res) < 0 Then
            res = CStr(CLng(res) + 10)
        End If
        total = Right$(res, 1) & total
        If Len(res) - 1 < 1 Then
            resto = "0"
        Else
            resto = Left$(res, Len(res) - 1)
        End If
    Next
    If resto <> "0" Then
        total = resto & total
    End If
    '
    restar2Filas = total
End Function
'
Private Sub swap(ByRef n1 As String, ByRef n2 As String)
    Dim t As String
    t = n1
    n1 = n2
    n2 = t
End Sub

 




 


La fecha/hora en el servidor es: 23/12/2024 3:36:39

La fecha actual GMT (UTC) es: 

©Guillermo 'guille' Som, 1996-2024