11111010111 1010 1011

Programar por Programar


¿Te gusta programar?
Inicio


El código fuente de la estructura BigInt


Publicado: 22/Oct/2007
Actualizado: 22/oct/2007
Autor: Guillermo 'guille' Som


 

Contenido

Pues eso... el código fuente de la estructura BigInt.


El código de BigInt
'------------------------------------------------------------------------------
' BigInt                                                            (19/Oct/07)
' Estructura basada en BigInt de F#
' Se necesita una referencia a fslib.dll
'
' Se debe configurar para que no haya overflow en números enteros
'
' El espacio de nombres de esta librería es:
' elGuille.Developer.FSharp
'
' ©Guillermo 'guille' Som, 2007
'------------------------------------------------------------------------------
Option Strict On

Imports Microsoft.VisualBasic
Imports System

Imports System.Text

Imports System.Reflection
Imports System.Diagnostics

Imports fsm = Microsoft.FSharp.Math
Imports fsc = Microsoft.FSharp.Core

' Alias para el tipo con las funciones
Imports fsbim = Microsoft.FSharp.Math.BigIntModule


''' <summary>
''' Estructura para manejar números enteros
''' de gran preción.
''' Internamente se usa el tipo BigInt de F#
''' Esta estructura es el tipo usado por 
''' las otras estructuras de esta librería.
''' Necesita la librería fslib.dll de F#
''' y actualmente utiliza la versión 1.9.2.9
''' </summary>
''' <remarks>
''' Iniciado: 19/Oct/2007
''' Revisado: 22/Oct/2007
''' </remarks>
Public Structure BigInt
    Implements IComparable

    ''' <summary>
    ''' Para la interfaz IComparable
    ''' </summary>
    ''' <param name="obj"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function CompareTo(ByVal obj As Object) As Integer _
                Implements System.IComparable.CompareTo
        Return String.Compare(Me.ToString, obj.ToString)
    End Function


    Private m_Value As fsm.BigInt
    ''' <summary>
    ''' El valor del BigInt interno
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Value() As fsm.BigInt
        Get
            Return m_Value
        End Get
        Set(ByVal value As fsm.BigInt)
            m_Value = value
        End Set
    End Property


    '
    ' Métodos compartidos
    '

    ''' <summary>
    ''' Suma dos BigInt
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Add(ByVal num1 As BigInt, ByVal num2 As BigInt) As BigInt
        Return fsbim.add(num1, num2)
    End Function

    ''' <summary>
    ''' Valor absoluto del BigInt
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Abs(ByVal num1 As BigInt) As BigInt
        Return fsbim.abs(num1)
    End Function

    ''' <summary>
    ''' Compara dos BigInt
    ''' Devuelve 0 si son iguales
    ''' -1 si el primero es menor
    '''  1 si el primero es mayor
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Compare(ByVal num1 As BigInt, ByVal num2 As BigInt) As Integer
        Return fsbim.compare(num1.Value, num2.Value)
    End Function

    ''' <summary>
    ''' Divide dos BigInt
    ''' Devuelve la parte entera
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Div(ByVal num1 As BigInt, ByVal num2 As BigInt) As BigInt
        Return fsbim.div(num1, num2)
    End Function

    ''' <summary>
    ''' Devuelve el resto (módulo) de dividir los dos números indicados
    ''' La parte entera la devuelve por referencia en el tercer parámetro
    ''' En realidad es un num1 Mod num2 lo que se devuelve
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <param name="num3"></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' Esta sobrecarga no tiene equivalente directo en F#
    ''' pero la dejo junto a los otros Div
    ''' </remarks>
    Public Shared Function Div(ByVal num1 As BigInt, ByVal num2 As BigInt, _
                               ByRef num3 As BigInt) As BigInt
        Dim bi3 As fsc.Tuple(Of fsm.BigInt, fsm.BigInt) = fsm.BigIntModule.divmod(num1, num2)
        num3 = bi3.Item1
        Return bi3.Item2
    End Function

    ''' <summary>
    ''' Devuelve el resto (módulo) de dividir los dos números indicados
    ''' La parte entera la devuelve por referencia en el tercer parámetro
    ''' En realidad es un num1 Mod num2 lo que se devuelve
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <param name="num3"></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' Esta sobrecarga no tiene equivalente directo en F#
    ''' pero la dejo junto a los otros Div
    ''' </remarks>
    Public Shared Function DivRem(ByVal num1 As BigInt, ByVal num2 As BigInt, _
                                  ByRef num3 As BigInt) As BigInt
        Return Div(num1, num2, num3)
    End Function


    ''' <summary>
    ''' Devuelve la división y el resto
    ''' El resto se devuelve y el valor entero se asigna al tercer parámetro
    ''' En realidad es un num1 Mod num2 lo que se devuelve
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <param name="num3"></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' Hay que tener en cuenta (para los que no somos expertos en matemáticas)
    ''' que el resto en realidad es el resto de la división
    ''' no la parte fraccionaria:
    ''' Por ejemplo: 125 / 15 dará 8 y 5 en lugar de 8 y 0.3333333.
    ''' Esta sobrecarga no tiene equivalente directo en F#
    ''' </remarks>
    Public Shared Function DivMod(ByVal num1 As BigInt, ByVal num2 As BigInt, _
                                  ByRef num3 As BigInt) As BigInt
        Dim bi3 As fsc.Tuple(Of fsm.BigInt, fsm.BigInt) = _
                                            fsm.BigIntModule.divmod(num1, num2)
        num3 = bi3.Item1
        Return bi3.Item2
    End Function

    ''' <summary>
    ''' Devuelve el resto de la división
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function DivMod(ByVal num1 As BigInt, ByVal num2 As BigInt) As BigInt
        Return fsbim.[rem](num1, num2)
    End Function

    ''' <summary>
    ''' Devuelve True si los dos números son iguales
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Equal(ByVal num1 As BigInt, ByVal num2 As BigInt) As Boolean
        Return fsbim.equal(num1, num2)
    End Function

    ''' <summary>
    ''' Devuelve el factorial del número indicado
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Factorial(ByVal num1 As BigInt) As BigInt
        Return fsbim.factorial(num1)
    End Function

    ''' <summary>
    ''' Devuelve True si el primer número es mayor que el segundo
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GT(ByVal num1 As BigInt, ByVal num2 As BigInt) As Boolean
        Return fsbim.gt(num1, num2)
    End Function

    ''' <summary>
    ''' Devuelve True si el primer número es mayor o igual que el segundo
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GTE(ByVal num1 As BigInt, ByVal num2 As BigInt) As Boolean
        Return fsbim.gte(num1, num2)
    End Function

    Public Shared Function Hash(ByVal num1 As BigInt) As Integer
        Return fsbim.hash(num1)
    End Function

    Public Shared Function HCF(ByVal num1 As BigInt, ByVal num2 As BigInt) As BigInt
        Return fsbim.hcf(num1, num2)
    End Function

    ''' <summary>
    ''' Devuelve True si es el número 1
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function IsOne(ByVal num1 As BigInt) As Boolean
        Return fsbim.isOne(num1)
    End Function

    ''' <summary>
    ''' Devuelve True si es cero
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function IsZero(ByVal num1 As BigInt) As Boolean
        Return fsbim.isZero(num1)
    End Function

    ''' <summary>
    ''' Devuelve True si el primer número es menor que el segundo
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function LT(ByVal num1 As BigInt, ByVal num2 As BigInt) As Boolean
        Return fsbim.lt(num1, num2)
    End Function

    ''' <summary>
    ''' Devuelve True si el primer número es menor o igual que el segundo
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function LTE(ByVal num1 As BigInt, ByVal num2 As BigInt) As Boolean
        Return fsbim.lte(num1, num2)
    End Function

    ''' <summary>
    ''' Devuelve el valor mayor de los dos indicados
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Max(ByVal num1 As BigInt, ByVal num2 As BigInt) As BigInt
        Return fsbim.max(num1, num2)
    End Function

    ''' <summary>
    ''' Devuelve el valor menor de los dos indicados
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Min(ByVal num1 As BigInt, ByVal num2 As BigInt) As BigInt
        Return fsbim.min(num1, num2)
    End Function

    ''' <summary>
    ''' Multiplica los dos números
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Mul(ByVal num1 As BigInt, ByVal num2 As BigInt) As BigInt
        Return fsbim.mul(num1, num2)
    End Function

    ''' <summary>
    ''' Devuelve el número en formato negativo
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Neg(ByVal num1 As BigInt) As BigInt
        Return fsbim.neg(num1.Value)
    End Function

    ''' <summary>
    ''' Devuelve True si el número es negativo
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Negative(ByVal num1 As BigInt) As Boolean
        Return fsbim.negative(num1.Value)
    End Function

    ''' <summary>
    ''' Devuelve un valor 1
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared ReadOnly Property One() As BigInt
        Get
            Return fsbim.one
        End Get
    End Property

    ''' <summary>
    ''' Devuelve True si el número es positivo
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Positive(ByVal num1 As BigInt) As Boolean
        Return fsbim.positive(num1.Value)
    End Function

    ''' <summary>
    ''' Devuelve el número elevado a la potencia indicada en el segundo parámetro
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Pow(ByVal num1 As BigInt, ByVal num2 As BigInt) As BigInt
        Return fsbim.pow(num1, num2)
    End Function

    ''' <summary>
    ''' Devuelve el número elevado a la potencia indicada en el segundo parámetro
    ''' El segundo parámetro es de tipo Int32
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Pow(ByVal num1 As BigInt, ByVal num2 As Integer) As BigInt
        Return fsbim.powi(num1, num2)
    End Function

    ''' <summary>
    ''' Devuelve el número elevado a la potencia indicada en el segundo parámetro
    ''' El segundo parámetro es de tipo Int32
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function PowI(ByVal num1 As BigInt, ByVal num2 As Integer) As BigInt
        Return fsbim.powi(num1, num2)
    End Function

    ''' <summary>
    ''' Devuelve el resto de la división
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function [Rem](ByVal num1 As BigInt, ByVal num2 As BigInt) As BigInt
        Return fsbim.[rem](num1, num2)
    End Function

    ''' <summary>
    ''' Devuelve el resto de la división
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function [Mod](ByVal num1 As BigInt, ByVal num2 As BigInt) As BigInt
        Return fsbim.[rem](num1, num2)
    End Function

    ''' <summary>
    ''' El máximo de decimales a devolver
    ''' </summary>
    ''' <remarks></remarks>
    Public Const MaxDecimalesMaxValue As Integer = 1000 ' 19
    ''' <summary>
    ''' El mínimo de decimales a devolver
    ''' </summary>
    ''' <remarks></remarks>
    Public Const MaxDecimalesMinValue As Integer = 0
    ''' <summary>
    ''' La misma precisión (30) que la calculadora de Windows
    ''' </summary>
    ''' <remarks></remarks>
    Private Shared m_MaxDecimales As Integer = 30

    ''' <summary>
    ''' Número máximo de decimales a mostrar en las fracciones
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Property MaxDecimales() As Integer
        Get
            Return m_MaxDecimales
        End Get
        Set(ByVal value As Integer)
            If value < MaxDecimalesMinValue Then
                m_MaxDecimales = MaxDecimalesMinValue
            ElseIf value > MaxDecimalesMaxValue Then
                m_MaxDecimales = MaxDecimalesMaxValue
            Else
                m_MaxDecimales = value
            End If
        End Set
    End Property

    ''' <summary>
    ''' Ni idea, pero parece que multiplica los dos números
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Scale(ByVal num1 As Integer, ByVal num2 As BigInt) As BigInt
        Return fsbim.scale(num1, num2)
    End Function

    ''' <summary>
    ''' Devuleve el signo del número:
    ''' 1 es positivo, -1 es negativo
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Sign(ByVal num1 As BigInt) As Integer
        Return fsbim.sign(num1)
    End Function

    ''' <summary>
    ''' Resta los dos números
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function [Sub](ByVal num1 As BigInt, ByVal num2 As BigInt) As BigInt
        Return fsbim.sub(num1, num2)
    End Function

    ''' <summary>
    ''' Convierte el número en un Int32 (Integer)
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function ToInt32(ByVal num1 As BigInt) As Integer
        Return fsbim.to_int(num1)
    End Function

    ''' <summary>
    ''' Convierte el número en un Int64 (Long)
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function ToInt64(ByVal num1 As BigInt) As Long
        Return fsbim.to_int64(num1)
    End Function

    ''' <summary>
    ''' Convierte el número en un Double
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function ToDouble(ByVal num1 As BigInt) As Double
        Return fsbim.to_float(num1)
    End Function

    ''' <summary>
    ''' Convierte el número en una cadena
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Overloads Shared Function ToString(ByVal num1 As BigInt) As String
        Return fsbim.to_string(num1)
    End Function

    ''' <summary>
    ''' Devuelve el valor cero
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared ReadOnly Property Zero() As BigInt
        Get
            Return fsbim.zero
        End Get
    End Property


    ''' <summary>
    ''' Convertir otros tipos a BigInt
    ''' </summary>
    ''' <param name="num">
    ''' Puede ser un String o 
    ''' un valor numérico que se convertirá a Int64
    ''' </param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Parse(ByVal num As String) As BigInt
        If num.Contains("E") Then
            num = num.Substring(0, num.IndexOf("E"))
        ElseIf num.StartsWith("N") Then
            num = "0"
        End If
        Return New BigInt(fsbim.of_string(num))
    End Function

    ''' <summary>
    ''' Convierte un Double en BigInt
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Parse(ByVal num As Double) As BigInt
        Return New BigInt(fsbim.of_int64(CLng(num)))
    End Function

    ''' <summary>
    ''' Convierte un BigInt de F# en BigInt
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Parse(ByVal num As fsm.BigInt) As BigInt
        Return New BigInt(num)
    End Function



    '
    ' Funciones que no están en el tipo de F#
    '


    ''' <summary>
    ''' Devuelve el mayor de la lista indicada
    ''' </summary>
    ''' <param name="parametros"></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' Para que este método funcione hay que implementar IComparable
    ''' </remarks>
    Public Shared Function Max(ByVal ParamArray parametros() As BigInt) As BigInt
        Array.Sort(parametros)
        Return parametros(parametros.Length - 1)
    End Function

    ''' <summary>
    ''' Devuelve el menor de la lista indicada
    ''' </summary>
    ''' <param name="parametros"></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' Para que este método funcione hay que implementar IComparable
    ''' </remarks>
    Public Shared Function Min(ByVal ParamArray parametros() As BigInt) As BigInt
        Array.Sort(parametros)
        Return parametros(0)
    End Function

    ''' <summary>
    ''' Devuelve la suma de todos los valores indicados
    ''' </summary>
    ''' <param name="parametros"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Suma(ByVal ParamArray parametros() As BigInt) As BigInt
        Dim t As BigInt = parametros(0)
        For i As Integer = 1 To parametros.Length - 1
            t = t + parametros(i)
        Next
        Return t
    End Function

    ''' <summary>
    ''' Suma el contenido de un array con otros valores
    ''' </summary>
    ''' <param name="numeros"></param>
    ''' <param name="parametros"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Suma(ByVal numeros() As BigInt, _
                                ByVal ParamArray parametros() As BigInt) As BigInt
        Dim t As BigInt = parametros(0)
        For i As Integer = 1 To parametros.Length - 1
            t = t + parametros(i)
        Next
        For i As Integer = 0 To numeros.Length - 1
            t = t + numeros(i)
        Next
        Return t
    End Function

    ''' <summary>
    ''' Devuelve la media aritmética de los números indicados
    ''' El valor devuelto es de tipo entero BigInt
    ''' </summary>
    ''' <param name="parametros"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Media(ByVal ParamArray parametros() As BigInt) As BigInt
        Dim t As BigInt = Suma(parametros)
        Return t \ parametros.Length
    End Function

    ''' <summary>
    ''' Devuelve la media del total y la cantidad indicadas
    ''' Esto es válido para calcular primero con Suma
    ''' </summary>
    ''' <param name="total"></param>
    ''' <param name="cant"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Media(ByVal total As BigInt, ByVal cant As BigInt) As BigInt
        Return total \ cant
    End Function

    ''' <summary>
    ''' Devuelve el porcentaje del primero número sobre el segundo:
    ''' num1 * num2 / 100
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Porcentaje(ByVal num1 As BigInt, ByVal num2 As BigInt) As BigInt
        Return num1 * num2 / 100
    End Function

    ''' <summary>
    ''' La versión actual de la DLL (revisión)
    ''' </summary>
    ''' <param name="conNombre">
    ''' Opcional (False) si se debe devolver el nombre del ensamblado
    ''' </param>
    ''' <returns>
    ''' La versión de la DLL (versión de FileVersion)
    ''' </returns>
    ''' <remarks></remarks>
    Public Shared Function Version(ByVal conNombre As Boolean) As String
        Dim ensamblado As Assembly = Assembly.GetExecutingAssembly
        Dim fvi As FileVersionInfo = FileVersionInfo.GetVersionInfo(ensamblado.Location)
        If conNombre Then
            Return ensamblado.GetName.Name & " v" & fvi.FileVersion
        Else
            Return " v" & fvi.FileVersion
        End If
    End Function

    ''' <summary>
    ''' La versión actual de la DLL (revisión)
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Version() As String
        Return Version(False)
    End Function

    ''' <summary>
    ''' El factor mayor de un número (factorMax)
    ''' El númeo mayor que divide exactamente al número
    ''' Si no lo hay ninguno, devuelve cero (normalmente será primo)
    ''' </summary>
    ''' <param name="a"></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' Esta operación es lenta si el número es muy grande
    ''' </remarks>
    Public Shared Function FactorMayor(ByVal a As BigInt) As BigInt
        Dim i As BigInt = System.Math.Sqrt(a) + 1
        Dim bi2 As BigInt = 2
        While BigInt.GT(i, bi2)
            If BigInt.Equal(BigInt.Mod(a, i), BigInt.Zero) Then
                Return i
            End If
            'If a Mod i = BigInt.Zero Then
            '    Return i
            'End If
            i = BigInt.Sub(i, BigInt.One)
            'i = i - BigInt.One
        End While

        Return BigInt.Zero
    End Function


    ''' <summary>
    ''' Devuelve el factor menor de un número
    ''' El número menor que lo divide exactamente
    ''' Si no hay, devuelve cero (normalmente será número primo)
    ''' </summary>
    ''' <param name="a"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function FactorMenor(ByVal a As BigInt) As BigInt
        ' Si es divisible por dos
        Dim bi2 As BigInt = 2
        If BigInt.Equal(BigInt.Mod(a, bi2), BigInt.Zero) Then
            Return bi2
        End If
        'If a Mod 2 = 0 Then
        '    Return 2
        'End If

        ' Comprobar desde el 3 hasta la raíz cuadrada
        ' seguir comprobando de dos en dos
        Dim m As BigInt = System.Math.Sqrt(a) + 1
        Dim i As BigInt = 3
        While i < m
            If BigInt.Equal(BigInt.Mod(a, i), BigInt.Zero) Then
                Return i
            End If
            i = BigInt.Add(i, bi2)
            'If a Mod i = 0 Then
            '    Return i
            'End If
            'i = i + 2
        End While

        Return BigInt.Zero
    End Function


    ''' <summary>
    ''' Comprueba si el número es primo
    ''' Devuelve True si es primo, o False si no lo es
    ''' El número 1 se considera como primo
    ''' </summary>
    ''' <param name="a"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function EsPrimo(ByVal a As BigInt) As Boolean
        If a = 1 OrElse a = 2 OrElse a = 3 Then
            Return True
        End If

        ' Si es par, no es primo
        Dim bi2 As BigInt = 2
        If BigInt.Equal(BigInt.Mod(a, bi2), BigInt.Zero) Then
            Return False
        End If
        'If a Mod 2 = 0 Then
        '    Return 0
        'End If

        ' Empezar a comprobar desde el 3
        ' hasta la raíz cuadrada del número
        Dim m As BigInt = System.Math.Sqrt(a) + 1
        Dim i As BigInt = 3
        While i < m
            ' Si es divisible por i, es que no es primo
            If BigInt.Equal(BigInt.Mod(a, i), BigInt.Zero) Then
                Return False
            End If
            i = BigInt.Add(i, bi2)
            'If a Mod i = 0 Then
            '    Return 0
            'End If
            'i = i + 2
        End While

        Return True
    End Function

    ''' <summary>
    ''' La raíz cuadrada de un número
    ''' El valor máximo es el de un Double
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Sqrt(ByVal num As BigInt) As BigInt
        Return System.Math.Sqrt(num)
    End Function


    ''' <summary>
    ''' Suma dos números
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Sum(ByVal num1 As BigInt, ByVal num2 As BigInt) As BigInt
        Return fsbim.add(num1, num2)
    End Function


    ''' <summary>
    ''' Divide dos números
    ''' Devuelve la parte fraccionaria (máximo MaxDecimales dígitos)
    ''' En el tercer parámetro se devuelve la parte entera
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <param name="num2"></param>
    ''' <param name="num3"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function DivFrac(ByVal num1 As BigInt, ByVal num2 As BigInt, _
                                   ByRef num3 As BigInt) As String
        Dim bi3 As fsc.Tuple(Of fsm.BigInt, fsm.BigInt) = _
                                                fsm.BigIntModule.divmod(num1, num2)
        num3 = bi3.Item1 ' Parte entera

        Dim bi4 As BigInt = bi3.Item2
        Dim sb As New System.Text.StringBuilder
        Dim n3 As BigInt = BigInt.Zero

        For i As Integer = 1 To MaxDecimales
            num1 = bi4 * 10
            bi4 = BigInt.DivMod(num1, num2, n3)
            sb.Append(BigInt.Abs(n3).ToString)
        Next

        Return sb.ToString().TrimEnd("0".ToCharArray)
    End Function


    ''' <summary>
    ''' Devuelve PI como número entero con 260 decimales
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks>
    ''' No creo que tenga utilidad, pero...
    ''' </remarks>
    Public Shared ReadOnly Property PI() As BigInt
        Get
            ' Valor de la página
            ' http://centros5.pntic.mec.es/ies.de.bullas/dp/matema/conocer/pi_1500.htm

            Dim s As New StringBuilder(260)
            s.Append("3")
            s.Append("14159265358979323846264338327950288419716939937510")
            s.Append("58209749445923078164062862089986280348253421170679")
            s.Append("82148086513282306647093844609550582231725359408128")
            s.Append("48111745028410270193852110555964462294895493038196")
            s.Append("44288109756659334461284756482337867831652712019091")
            ' Si añades más decimales, recuerda redondear si es necesario
            ' aquí tienes hasta el dígito 440 (que puedes usar sin redondear)
            ' 4564856692 3460348610 4543266482 1339360726 0249141273
            ' 7245870066 0631558817 4881520920 9628292540 9171536436
            ' 7892590360 0113305305 4882046652 1384146951 9415116094
            ' 7363717872 1468440901 2249534301 4654958537

            Return Parse(s.ToString)
        End Get
    End Property


    ''' <summary>
    ''' Devuelve el
    ''' Máximo Común Divisor / Greatest Common Divisor
    ''' </summary>
    ''' <param name="a"></param>
    ''' <param name="b"></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' Usa el teorema de Euclides mejorado
    ''' </remarks>
    Public Shared Function MCD(ByVal a As BigInt, ByVal b As BigInt) As BigInt
        While a > 0
            Dim c As BigInt = a
            a = b Mod a
            b = c
        End While

        Return b
    End Function

    ''' <summary>
    ''' Devuelve el
    ''' Máximo Común Divisor / Greatest Common Divisor
    ''' </summary>
    ''' <param name="a"></param>
    ''' <param name="b"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GCD(ByVal a As BigInt, ByVal b As BigInt) As BigInt
        Return MCD(a, b)
    End Function

    ''' <summary>
    ''' Mínimo Común Múltiplo / Least Common Multiple
    ''' Es el producto de dos números dividido por el mcd
    ''' </summary>
    ''' <param name="a"></param>
    ''' <param name="b"></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' </remarks>
    Public Shared Function MCM(ByVal a As BigInt, ByVal b As BigInt) As BigInt
        Dim c As BigInt = MCD(a, b)
        Dim t As BigInt = a * b

        Return t \ c
    End Function

    ''' <summary>
    ''' Mínimo Común Múltiplo / Least Common Multiple
    ''' Es el producto de dos números dividido por el mcd
    ''' </summary>
    ''' <param name="a"></param>
    ''' <param name="b"></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' </remarks>
    Public Shared Function LCM(ByVal a As BigInt, ByVal b As BigInt) As BigInt
        Return MCM(a, b)
    End Function



    '
    ' Constructores personalizados
    '

    ''' <summary>
    ''' Crear un nuevo objeto a partir de una cadena o 
    ''' un valor numérico que se convertirá a Int64
    ''' </summary>
    ''' <param name="num"></param>
    ''' <remarks></remarks>
    Public Sub New(ByVal num As String)
        Value = Parse(num)
    End Sub

    ''' <summary>
    ''' Crea un objeto a partir de un Double
    ''' </summary>
    ''' <param name="num"></param>
    ''' <remarks></remarks>
    Public Sub New(ByVal num As Double)
        Value = Parse(num)
    End Sub

    ''' <summary>
    ''' Crea un objeto a partir de un BigInt de F#
    ''' </summary>
    ''' <param name="num"></param>
    ''' <remarks></remarks>
    Public Sub New(ByVal num As fsm.BigInt)
        Value = num
    End Sub

    '
    ' Métodos de instancia
    '

    ''' <summary>
    ''' Devuelve el número como una cadena
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Overrides Function ToString() As String
        Return fsbim.to_string(Value)
    End Function


    ''' <summary>
    ''' Devuelve True si este número es cero
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function IsZero() As Boolean
        Return fsbim.isZero(Me.Value)
    End Function

    ''' <summary>
    ''' Convierte el número en un Int32 (Integer)
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function ToInt32() As Integer
        Return fsbim.to_int(Me.Value)
    End Function

    ''' <summary>
    ''' Convierte el número en un Int64 (Long)
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function ToInt64() As Long
        Return fsbim.to_int64(Me.Value)
    End Function

    ''' <summary>
    ''' Convierte el número en un Double
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function ToDouble() As Double
        Return fsbim.to_float(Me.Value)
    End Function

    '
    ' Conversiones personalizadas
    '

    ''' <summary>
    ''' Convierte un BigInt de F# en un BigInt
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Widening Operator CType(ByVal num As fsm.BigInt) As BigInt
        Return Parse(num)
    End Operator

    ''' <summary>
    ''' Convierte un BigInt en un BigInt de F#
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Widening Operator CType(ByVal num As BigInt) As fsm.BigInt
        Return num.Value
    End Operator

    ''' <summary>
    ''' Convierte un valor numérico en un BigInt
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Widening Operator CType(ByVal num As Double) As BigInt
        Return Parse(num)
    End Operator

    ''' <summary>
    ''' Convierte un ULong en un BigInt
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Widening Operator CType(ByVal num As ULong) As BigInt
        Return Parse(num.ToString)
    End Operator

    ''' <summary>
    ''' Convierte una cadena en un BigInt
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Widening Operator CType(ByVal num As String) As BigInt
        Return Parse(num)
    End Operator

    ' Conversiones de BigInt a otros tipos

    ''' <summary>
    ''' Convierte un BigInt en una cadena
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Widening Operator CType(ByVal num As BigInt) As String
        Return fsbim.to_string(num.Value)
    End Operator



    ' Estos pueden tener pérdida de información

    ' Dejo estas sobrecargas para que se puedan convertir más o menos bien

    ''' <summary>
    ''' Convierte un BigInt en un Double
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Widening Operator CType(ByVal num As BigInt) As Double
        Return fsbim.to_float(num.Value)
    End Operator

    ''' <summary>
    ''' Convierte un BigInt en un Int64 (Long)
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Narrowing Operator CType(ByVal num As BigInt) As Long
        Return fsbim.to_int64(num.Value)
    End Operator

    ''' <summary>
    ''' Convierte un BigInt en un Int32 (Integer)
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Narrowing Operator CType(ByVal num As BigInt) As Integer
        Return fsbim.to_int(num.Value)
    End Operator

    ''' <summary>
    ''' Convierte un BigInt en un UInt32 (UInteger)
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Narrowing Operator CType(ByVal num As BigInt) As UInteger
        Return CUInt(fsbim.to_int64(num.Value))
    End Operator

    ' El valor máximo de ULong es:
    ' 18.446.744.073.709.551.615 / 0xFFFFFFFFFFFFFFFF
    ''' <summary>
    ''' Convierte un BigInt en un UInt64 (ULong)
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Narrowing Operator CType(ByVal num As BigInt) As ULong
        Return CULng(fsbim.to_int64(num.Value))
        ''Return CULng(fsbim.to_string(num.Value))
    End Operator

    ' El valor máximo de un decimal es:
    ' 79228162514264337593543950335 (29 cifras)
    ' 79.228.162.514.264.337.593.543.950.335
    ''' <summary>
    ''' Convierte un BigInt en un Decimal
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Narrowing Operator CType(ByVal num As BigInt) As Decimal
        Try
            Return CDec(fsbim.to_string(num.Value))
        Catch ex As Exception
            'Return Decimal.MaxValue
            Return CULng(fsbim.to_int64(num.Value))

        End Try
    End Operator


    '
    ' Sobrecarga de operadores
    '

    '
    ' Sobrecarga de operadores aritméticos
    '

    ''' <summary>
    ''' Operador unario devuelve el mismo número
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Operator +(ByVal bn1 As BigInt) As BigInt
        Return bn1
    End Operator

    ''' <summary>
    ''' Operador unario, niega el número
    ''' Si es positivo lo devuelve negativo y viceversa
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Operator -(ByVal bn1 As BigInt) As BigInt
        Return BigInt.Neg(bn1)
    End Operator

    ''' <summary>
    ''' Suma dos valores
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Operator +(ByVal bn1 As BigInt, ByVal bn2 As BigInt) As BigInt
        Return BigInt.Add(bn1, bn2)
    End Operator

    ''' <summary>
    ''' Resta dos valores
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Operator -(ByVal bn1 As BigInt, ByVal bn2 As BigInt) As BigInt
        Return BigInt.Sub(bn1, bn2)
    End Operator

    ''' <summary>
    ''' Multiplica dos valores
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Operator *(ByVal bn1 As BigInt, ByVal bn2 As BigInt) As BigInt
        Return BigInt.Mul(bn1, bn2)
    End Operator

    ''' <summary>
    ''' Divide dos valores
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Operator /(ByVal bn1 As BigInt, ByVal bn2 As BigInt) As BigInt
        Return BigInt.Div(bn1, bn2)
    End Operator

    ''' <summary>
    ''' Divide dos valores
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Operator \(ByVal bn1 As BigInt, ByVal bn2 As BigInt) As BigInt
        Return BigInt.Div(bn1, bn2)
    End Operator

    ''' <summary>
    ''' Devuelve el resto de la división del primero por el segundo
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Operator Mod(ByVal bn1 As BigInt, ByVal bn2 As BigInt) As BigInt
        Return BigInt.Mod(bn1, bn2)
    End Operator

    ''' <summary>
    ''' Eleva el primero número a la potencia indicada en el segundo
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Operator ^(ByVal bn1 As BigInt, ByVal bn2 As BigInt) As BigInt
        Return BigInt.Pow(bn1, bn2)
    End Operator

    ''' <summary>
    ''' Sobrecarga del operador de concatenación
    ''' entre dos BigInt
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' v.0.1 19/Oct/07
    ''' </remarks>
    Public Shared Operator &(ByVal bn1 As BigInt, ByVal bn2 As BigInt) As String
        Return bn1.ToString & bn2.ToString
    End Operator

    ' Estas dos sobrecargas es para evitar convertir una cadena a BigInt
    ' cuando los parámetros no son BigInt
    ''' <summary>
    ''' Sobrecarga del operador de concatenación entre un BigInt y una cadena
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Operator &(ByVal bn1 As BigInt, ByVal bn2 As String) As String
        Return bn1.ToString & bn2
    End Operator

    ''' <summary>
    ''' Sobrecarga del operador de concatenación entre una cadena y un BigInt
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Operator &(ByVal bn1 As String, ByVal bn2 As BigInt) As String
        Return bn1 & bn2.ToString
    End Operator


    '
    ' Sobrecarga de operadores de comparación
    '

    ''' <summary>
    ''' Devuelve True si son iguales
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Operator =(ByVal bn1 As BigInt, ByVal bn2 As BigInt) As Boolean
        Return BigInt.Equal(bn1, bn2)
    End Operator

    ''' <summary>
    ''' Devuelve True si son distintos
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Operator <>(ByVal bn1 As BigInt, ByVal bn2 As BigInt) As Boolean
        Return Not BigInt.Equal(bn1, bn2)
    End Operator

    ''' <summary>
    ''' Devuelve True si el primero es menor
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Operator <(ByVal bn1 As BigInt, ByVal bn2 As BigInt) As Boolean
        Return BigInt.LT(bn1, bn2)
    End Operator

    ''' <summary>
    ''' Devuelve True si el primero es mayor
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Operator >(ByVal bn1 As BigInt, ByVal bn2 As BigInt) As Boolean
        Return BigInt.GT(bn1, bn2)
    End Operator

    ''' <summary>
    ''' Devuelve True si el primero es menor o igual
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Operator <=(ByVal bn1 As BigInt, ByVal bn2 As BigInt) As Boolean
        Return BigInt.LTE(bn1, bn2)
    End Operator

    ''' <summary>
    ''' Devuelve True si el primero es mayor o igual
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Operator >=(ByVal bn1 As BigInt, ByVal bn2 As BigInt) As Boolean
        Return BigInt.GTE(bn1, bn2)
    End Operator


    '
    ' Sobrecarga de operadores booleanos
    '

    ''' <summary>
    ''' Devuelve True si no es cero
    ''' </summary>
    ''' <param name="bn"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Operator IsTrue(ByVal bn As BigInt) As Boolean
        Return Not BigInt.IsZero(bn)
    End Operator

    ''' <summary>
    ''' Devuelve True si es cero
    ''' </summary>
    ''' <param name="bn"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Operator IsFalse(ByVal bn As BigInt) As Boolean
        Return BigInt.IsZero(bn)
    End Operator


End Structure


Programar por programar... ¡porque te gusta programar!
Ir al índice principal
Ir al sitio del Guille - Ir a los foros del Guille

Has entrado usando el host www.programarporprogramar.org