11111010111 1010 1011

Programar por Programar


¿Te gusta programar?
Inicio


El código fuente de la estructura BigFloat


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


 

Contenido

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


El código de BigFloat
'------------------------------------------------------------------------------
' BigFloat                                                          (20/Oct/07)
' Estructura para trabajar con números grandes con decimales
'
' 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.Threading

''' <summary>
''' Estructura para manejar números de gran precisoón
''' de coma flotante
''' </summary>
''' <remarks>
''' Iniciado: 20/Oct/2007
''' Revisado: 22/Oct/2007
''' </remarks>
Public Structure BigFloat
    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
        If TypeOf obj Is BigFloat Then
            Dim bf As BigFloat = obj.ToString
            Return Compare(Me, bf)
        Else
            'Return String.Compare(Me.ToString, obj.ToString)
            Return 0
        End If
    End Function

    ''' <summary>
    ''' El número completo incluida la parte fraccionaria
    ''' Si el número es 125.55
    ''' Entero será 12555 y
    ''' Decimales será 100
    ''' </summary>
    ''' <remarks></remarks>
    Friend Entero As BigInt
    ''' <summary>
    ''' La posición del decimal
    ''' Si el número es 125.55
    ''' Entero será 12555 y
    ''' Decimales será 100
    ''' </summary>
    ''' <remarks></remarks>
    Friend Decimales As BigInt

    ''' <summary>
    ''' Un valor cero para cuando haga falta 
    ''' no tener que estar calculándolo
    ''' </summary>
    ''' <remarks></remarks>
    Private Shared ReadOnly bigFloatZero As BigFloat
    ''' <summary>
    ''' Un valor uno para cuando haga falta 
    ''' no tener que estar calculándolo
    ''' </summary>
    ''' <remarks></remarks>
    Private Shared ReadOnly bigFloatOne As BigFloat '= BigInt.One
    ''' <summary>
    ''' Un valor dos para cuando haga falta 
    ''' no tener que estar calculándolo
    ''' </summary>
    ''' <remarks></remarks>
    Private Shared ReadOnly bigFloatTwo As BigFloat

    ''' <summary>
    ''' Para el separador de decimales
    ''' </summary>
    ''' <remarks></remarks>
    Private Shared ReadOnly sepDec As String

    ''' <summary>
    ''' Constructor compartido
    ''' se inicia el separador y los valores de 0, 1 y 2
    ''' </summary>
    ''' <remarks></remarks>
    Shared Sub New()
        sepDec = Thread.CurrentThread.CurrentCulture. _
                        NumberFormat.CurrencyDecimalSeparator

        bigFloatZero = New BigFloat(BigInt.Zero)
        bigFloatOne = New BigFloat(BigInt.One)
        bigFloatTwo = New BigFloat(2)
    End Sub

    ''' <summary>
    ''' Crea un nuevo objeto a partir de dos BigInt
    ''' </summary>
    ''' <param name="ent"></param>
    ''' <param name="dec"></param>
    ''' <remarks></remarks>
    Public Sub New(ByVal ent As BigInt, ByVal dec As BigInt)
        Entero = ent
        If dec.IsZero Then
            dec = bigFloatOne 'BigInt.One
        End If
        Decimales = dec
    End Sub

    ''' <summary>
    ''' Crea un nuevo objeto a partir de un BigInt
    ''' </summary>
    ''' <param name="ent"></param>
    ''' <remarks></remarks>
    Public Sub New(ByVal ent As BigInt)
        Entero = ent
        ' Usar BigInt.One y no bigFloatOne
        ' ya que a este constructor se llama antes de tener el valor
        Decimales = BigInt.One
    End Sub


    ' Parse permite crear nuevas instancias a partir de cadenas o enteros

    ''' <summary>
    ''' Convierte una cadena en un BigFloat
    ''' </summary>
    ''' <param name="s"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Parse(ByVal s As String) As BigFloat
        Dim bn1 As BigInt
        Dim i As Integer

        i = s.IndexOf(sepDec)
        If i = -1 Then
            Select Case sepDec
                Case ","
                    i = s.IndexOf(".")
                Case Else
                    i = s.IndexOf(",")
            End Select
        End If
        If i > -1 Then
            Dim s2 As String = s.Substring(i + 1)
            Dim s1 As String = s.Substring(0, i) & s2
            bn1 = s1
            Dim bn2 As BigInt = "1" & New String("0"c, Len(s2))

            Return New BigFloat(bn1, bn2)
        End If
        bn1 = s
        Return New BigFloat(bn1) ', 1)
    End Function

    ''' <summary>
    ''' Convierte un doble a BigFloat
    ''' </summary>
    ''' <param name="n"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Parse(ByVal n As Double) As BigFloat
        ' Tener en cuenta los valores del exponente
        ' Por ejemplo:
        ' 1,23456789012346E+16 es:
        ' 12345678901234600
        ' 1,23456789012346E-16 es:
        ' 0.000000000000000123456789012346
        ' 1,23456789012346E-17 es:
        ' 0.0000000000000000123456789012346
        ' 123.456789012346E-17
        ' 0.00000000000000123456789012346
        ' Cuando es positivo el separador suele estar en la segunda posición
        Dim s As String = n.ToString
        Dim i As Integer = InStr(s, "E")
        If i > 0 Then
            Dim signo As String = Mid(s, i + 1, 1)
            Dim digitos As Integer = CInt(Mid(s, i + 2))
            Dim pDec As Integer = InStr(s, sepDec)
            Dim sNum As String = Left(s, i - 1).Replace(sepDec, "")
            If signo = "-" Then
                ' En los negativos se pierden los ceros a la izquierda
                ' después del decimal,
                ' ya que se guarda como 0000000000000000123456789012346
                ' con los decimales correspondientes...
                ' Ya está corregido en el ToString
                Dim relleno As String = New String("0"c, digitos - pDec)
                s = "0" & sepDec & relleno & sNum
            Else
                Dim j As Integer = digitos - Len(sNum) + pDec - 1
                Dim relleno As String = New String("0"c, j)
                s = Left(sNum, pDec - 1) & Mid(sNum, pDec) & relleno
            End If
        End If
        Return Parse(s)
    End Function

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


    ''' <summary>
    ''' Convierte un BigFloat en un BigInt
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function ToBigInt(ByVal num As BigFloat) As BigInt
        Dim s As String = num
        Dim i As Integer = s.IndexOfAny(",.".ToCharArray)
        If i > -1 Then
            s = s.Substring(0, i)
        End If
        Return New BigInt(s)
    End Function


    ''' <summary>
    ''' Devuelve un BigFloat con valor cero
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared ReadOnly Property Zero() As BigFloat
        Get
            'Return New BigFloat(BigInt.Zero)
            Return bigFloatZero
        End Get
    End Property


    ''' <summary>
    ''' El valor de PI con 250 decimales
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared ReadOnly Property PI() As BigFloat
        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

            ' En realidad habría que devolver solo MaxDecimales
            Return Parse(s.ToString)
        End Get
    End Property

    ''' <summary>
    ''' El valor de E con 252 decimales
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared ReadOnly Property E() As BigFloat
        Get
            ' Valor de la página:
            ' http://antwrp.gsfc.nasa.gov/htmltest/gifcity/e.1mil

            Dim s As New StringBuilder(260)
            s.Append("2.")
            s.Append("71828182845904523536028747135266249775724709369995")
            s.Append("95749669676277240766303535475945713821785251664274")
            s.Append("27466391932003059921817413596629043572900334295260")
            s.Append("59563073813232862794349076323382988075319525101901")
            s.Append("15738341879307021540891499348841675092447614606680")
            s.Append("82")
            ' Si añades más decimales, recuerda redondear si es necesario
            ' aquí tienes hasta el dígito 439 (que puedes usar sin redondear)
            '   26480016 8477411853 7423454424 3710753907 7744992069
            ' 5517027618 3860626133 1384583000 7520449338 2656029760
            ' 6737113200 7093287091 2744374704 7230696977 2093101416
            ' 9283681902 5515108657 4637721112 523897844

            ' En realidad habría que devolver solo MaxDecimales
            Return Parse(s.ToString)
        End Get
    End Property

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


    ''' <summary>
    ''' Devuelve un BigNum con valor 2
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared ReadOnly Property Two() As BigFloat
        Get
            'Return New BigFloat(2)
            Return bigFloatTwo
        End Get
    End Property


    ''' <summary>
    ''' Devuelve True si el BigFloat indicado es cero
    ''' </summary>
    ''' <param name="n1"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function IsZero(ByVal n1 As BigFloat) As Boolean
        Return n1.Entero.IsZero 'AndAlso n1.Decimales.IsZero)
    End Function

    ''' <summary>
    ''' Devuelve True si este número es cero
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function IsZero() As Boolean
        Return Entero.IsZero 'AndAlso Decimales.IsZero)
    End Function


    ''' <summary>
    ''' Convierte el BigFloat indicado en un entero (Int32)
    ''' </summary>
    ''' <param name="n1"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function ToInt32(ByVal n1 As BigFloat) As Integer
        Try
            Return n1.Entero.ToInt32
        Catch ex As Exception
            Console.WriteLine("ERROR: " & ex.Message)
            Return 0
        End Try
    End Function

    ''' <summary>
    ''' Convierte este número en un entero (Int32)
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function ToInt32() As Integer
        Return BigInt.ToInt32(Me.Entero)
    End Function

    ''' <summary>
    ''' Devuelve el mayor de la lista indicada
    ''' </summary>
    ''' <param name="parametros"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Max(ByVal ParamArray parametros() As BigFloat) As BigFloat
        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></remarks>
    Public Shared Function Min(ByVal ParamArray parametros() As BigFloat) As BigFloat
        Array.Sort(parametros)
        Return parametros(0)
    End Function

    ''' <summary>
    ''' Devuelve el resto de la división
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function [Mod](ByVal bn1 As BigFloat, ByVal bn2 As BigFloat) As BigFloat
        Dim bf1 As BigFloat = BigInt.DivMod(bn1.Entero * bn2.Decimales, _
                                            bn2.Entero * bn1.Decimales)
        Dim bf2 As BigFloat = bn1.Decimales * bn2.Decimales

        Return bf1 / bf2
    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 BigFloat) As BigFloat
        Dim t As BigFloat = 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 BigFloat, _
                                ByVal ParamArray parametros() As BigFloat) As BigFloat
        Dim t As BigFloat = 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 BigFloat
    ''' </summary>
    ''' <param name="parametros"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Media(ByVal ParamArray parametros() As BigFloat) As BigFloat
        Dim t As BigFloat = 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 BigFloat, ByVal cant As BigFloat) As BigFloat
        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 BigFloat, _
                                      ByVal num2 As BigFloat) As BigFloat
        Return num1 * num2 / 100
    End Function

    ''' <summary>
    ''' Cambia el signo del número indicado
    ''' </summary>
    ''' <param name="num1"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Neg(ByVal num1 As BigFloat) As BigFloat
        num1.Entero = BigInt.Neg(num1.Entero)
        Return num1
    End Function



    ''' <summary>
    ''' Multiplica dos BigFloat
    ''' </summary>
    ''' <param name="n1"></param>
    ''' <param name="n2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Mul(ByVal n1 As BigFloat, ByVal n2 As BigFloat) As BigFloat
        ' 3.1 x 2.5 = 31x25 / 10x10
        Dim bn1 As BigInt = BigInt.Mul(n1.Entero, n2.Entero)
        Dim bn2 As BigInt = BigInt.Mul(n1.Decimales, n2.Decimales)

        Return New BigFloat(bn1, bn2)
    End Function

    ''' <summary>
    ''' Devuelve el resultado de dividir los dos números
    ''' </summary>
    ''' <param name="n1"></param>
    ''' <param name="n2"></param>
    ''' <returns></returns>
    ''' <remarks>
    ''' v.0.3 20/Oct/07
    ''' </remarks>
    Public Shared Function Div(ByVal n1 As BigFloat, ByVal n2 As BigFloat) As BigFloat
        Dim bn1 As BigInt = BigInt.Mul(n1.Entero, n2.Decimales)
        Dim bn2 As BigInt = BigInt.Mul(n2.Entero, n1.Decimales)

        Return DivBigIntToFloat(bn1, bn2)
    End Function

    ''' <summary>
    ''' Devuelve el resto de la división
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function DivMod(ByVal bn1 As BigFloat, ByVal bn2 As BigFloat) As BigFloat
        Return BigFloat.Mod(bn1, bn2)
    End Function

    ''' <summary>
    ''' División entera (se redondea)
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function DivInt(ByVal bn1 As BigFloat, ByVal bn2 As BigFloat) As BigFloat
        Return Round(Div(bn1, bn2))
    End Function



    ''' <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 BigInt.MaxDecimales
        End Get
        Set(ByVal value As Integer)
            BigInt.MaxDecimales = value
        End Set
    End Property

    ''' <summary>
    ''' Divide dos BigInt y devuelve un BigFloat
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Shared Function DivBigIntToFloat(ByVal bn1 As BigInt, _
                                             ByVal bn2 As BigInt) As BigFloat
        Dim bn3 As BigInt = BigInt.Zero
        Dim s4 As String = BigInt.DivFrac(bn1, bn2, bn3)
        Dim s3 As String = bn3
        Dim bn5 As BigInt = (s3 & s4)
        Dim bi As BigInt = ("1" & New String("0"c, Len(s4)))

        Return New BigFloat(bn5, bi)
    End Function

    ''' <summary>
    ''' Suma dos BigFloat
    ''' </summary>
    ''' <param name="n1"></param>
    ''' <param name="n2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Add(ByVal n1 As BigFloat, ByVal n2 As BigFloat) As BigFloat
        Dim bn1 As BigInt = BigInt.Add(n1.Entero * n2.Decimales, _
                                       n2.Entero * n1.Decimales)
        Dim bn2 As BigInt = BigInt.Mul(n1.Decimales, n2.Decimales)

        Return DivBigIntToFloat(bn1, bn2)
    End Function

    ''' <summary>
    ''' Resta los dos BigFloat indicados
    ''' </summary>
    ''' <param name="n1"></param>
    ''' <param name="n2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function [Sub](ByVal n1 As BigFloat, ByVal n2 As BigFloat) As BigFloat
        Dim bn1 As BigInt = BigInt.Sub(n1.Entero * n2.Decimales, _
                                       n2.Entero * n1.Decimales)
        Dim bn2 As BigInt = BigInt.Mul(n1.Decimales, n2.Decimales)

        Return DivBigIntToFloat(bn1, bn2)
    End Function


    ''' <summary>
    ''' Decrementa uno al BigFloat indicado
    ''' </summary>
    ''' <param name="n1"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Dec(ByVal n1 As BigFloat) As BigFloat
        Return BigFloat.Sub(n1, BigFloat.One)
    End Function

    ''' <summary>
    ''' Decrementa el primer BigFloat por la cantidad del segundo
    ''' (es como restarlos, en realidad es lo mismo que Sub)
    ''' </summary>
    ''' <param name="n1"></param>
    ''' <param name="n2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Dec(ByVal n1 As BigFloat, ByVal n2 As BigFloat) As BigFloat
        Return BigFloat.Sub(n1, n2)
    End Function

    ''' <summary>
    ''' Incrementa en uno el BigFloat indicado
    ''' </summary>
    ''' <param name="n1"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Inc(ByVal n1 As BigFloat) As BigFloat
        Return BigFloat.Add(n1, BigFloat.One)
    End Function

    ''' <summary>
    ''' Incrementa el primer BigFloat con el segundo
    ''' Es como sumarlos
    ''' </summary>
    ''' <param name="n1"></param>
    ''' <param name="n2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Inc(ByVal n1 As BigFloat, ByVal n2 As BigFloat) As BigFloat
        Return BigFloat.Add(n1, n2)
    End Function

    ''' <summary>
    ''' Comprueba si los dos números son iguales
    ''' </summary>
    ''' <param name="n1"></param>
    ''' <param name="n2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Iguales(ByVal n1 As BigFloat, _
                                   ByVal n2 As BigFloat) As Boolean
        If n1.Entero = n2.Entero AndAlso n1.Decimales = n2.Decimales Then
            Return True
        Else
            Return False
        End If
    End Function

    ''' <summary>
    ''' Devuelve True si los dos números son iguales
    ''' </summary>
    ''' <param name="n1"></param>
    ''' <param name="n2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Equal(ByVal n1 As BigFloat, _
                                 ByVal n2 As BigFloat) As Boolean
        Return Iguales(n1, n2)
    End Function

    ''' <summary>
    ''' Compara dos valores
    ''' Devuelve 0 si son iguales
    ''' -1 si el primero es menor
    ''' 1 si el primero es mayor
    ''' </summary>
    ''' <param name="n1"></param>
    ''' <param name="n2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Compare(ByVal n1 As BigFloat, _
                                   ByVal n2 As BigFloat) As Integer
        Dim bfr1 As BigFrac = n1
        Dim bfr2 As BigFrac = n2

        Return BigFrac.Compare(bfr1, bfr2)
    End Function


    ''' <summary>
    ''' Redondea el número al siguiente entero
    ''' si la fracción es superior a 0.5
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Round(ByVal num As BigFloat) As BigFloat
        num = num + 0.5
        Dim s As String = num
        Dim i As Integer = s.IndexOfAny(",.".ToCharArray)
        If i > -1 Then
            s = s.Substring(0, i)
        End If
        Return New BigFloat(s)
    End Function

    ''' <summary>
    ''' Redondea al siguiente número usando los decimales indicados
    ''' </summary>
    ''' <param name="num"></param>
    ''' <param name="decimales"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Round(ByVal num As BigFloat, _
                                 ByVal decimales As BigFloat) As BigFloat
        Dim j As Integer = CInt(decimales)
        If j < 1 Then Return num

        Dim s As String = num
        Dim i As Integer = s.IndexOfAny(",.".ToCharArray)
        If i = -1 Then
            Return num
        End If

        Dim decim As String = s.Substring(i + 1)
        If j > Len(decim) Then
            Return num
        End If

        Dim n2 As String = "1" & New String("0"c, Len(decim) - j)
        Dim bf As BigFloat = Parse(decim) / Parse(n2) + 0.5
        Dim bi As BigInt = bf
        Dim s1 As String = bi.ToString
        s = s.Substring(0, i) & sepDec & s1

        ' No devolver con New que se convierte a BigInt
        Return Parse(s) ' New BigFloat(s)
    End Function


    ''' <summary>
    ''' Eleva el primer número a la potencia del segundo
    ''' (no funciona bien con potencias decimales)
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Pow(ByVal bn1 As BigFloat, ByVal bn2 As BigFloat) As BigFloat
        Dim d2 As Double = CDbl(bn2)
        Return New BigFloat(BigInt.Pow(bn1.Entero, d2), BigInt.Pow(bn1.Decimales, d2))
    End Function


    '
    ' Métodos que usan Double para hacer los cálculos
    ' Todas o casi las funciones de System.Math
    ' (hasta que encuentre la forma de hacerlo con este tipo de datos)
    '
    ' Aunque no estén por orden alfabético, al principio
    ' pongo los métodos que usan el tipo de forma adecuda
    ' y después están los métodos que usan la clase System.Math
    ' y que por tanto solo tienen la precisión de Double.
    '
    ' También hay otros métodos que no están en System.Math
    '


    ''' <summary>
    ''' Devuelve el valor absoluto (positivo) del número
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Abs(ByVal num As BigFloat) As BigFloat
        If num < BigFloat.Zero Then
            Return (num * -BigFloat.One)
        Else
            Return num
        End If
    End Function

    ''' <summary>
    ''' Devuelve el siguiente número entero
    ''' Si es negativo se devuelve el mismo sin decimales
    ''' Si es positivo se devuelve el siguiente
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Ceiling(ByVal num As BigFloat) As BigFloat
        If num.IsZero Then
            Return num
        ElseIf num > BigFloat.Zero Then
            Return Truncate(num + BigFloat.One)
        Else
            Return Truncate(num)
        End If
    End Function

    ''' <summary>
    ''' Devuelve el entero anterior
    ''' Si es positivo devuelve el mismo número sin decimales
    ''' Si es negativo devuelve el número menos 1
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Floor(ByVal num As BigFloat) As BigFloat
        If num.IsZero Then
            Return num
        ElseIf num > BigFloat.Zero Then
            Return Truncate(num)
        Else
            Return Truncate(num - BigFloat.One)
        End If
    End Function

    ''' <summary>
    ''' Devuelve el signo del número
    ''' 0 si es cero
    ''' 1 si es positivo
    ''' -1 si es negativo
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Sign(ByVal num As BigFloat) As Integer
        If num.IsZero Then
            Return 0
        ElseIf num > BigFloat.Zero Then
            Return 1
        Else
            Return -1
        End If
    End Function

    ''' <summary>
    ''' Devuelve True si el número es negativo
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Negative(ByVal num As BigFloat) As Boolean
        Return Sign(num) = -1
    End Function

    ''' <summary>
    ''' Devuelve True si el número es positivo
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Positive(ByVal num As BigFloat) As Boolean
        Return Sign(num) = 1
    End Function

    ''' <summary>
    ''' Devuelve el número sin decimales
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Truncate(ByVal num As BigFloat) As BigFloat
        Dim bi As BigInt = BigFloat.ToBigInt(num)
        Return Parse(bi)
    End Function

    ''' <summary>
    ''' Devuelve el número sin decimales
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Fix(ByVal num As BigFloat) As BigFloat
        Return Truncate(num)
    End Function



    Public Shared Function Acos(ByVal num As BigFloat) As BigFloat
        Return BigFloat.Parse(System.Math.Acos(CDbl(num)))
    End Function

    Public Shared Function Asin(ByVal num As BigFloat) As BigFloat
        Return BigFloat.Parse(System.Math.Asin(CDbl(num)))
    End Function

    Public Shared Function Atan(ByVal num As BigFloat) As BigFloat
        Return BigFloat.Parse(System.Math.Atan(CDbl(num)))
    End Function

    Public Shared Function Atan2(ByVal num1 As BigFloat, _
                                 ByVal num2 As BigFloat) As BigFloat
        Return BigFloat.Parse(System.Math.Atan2(CDbl(num1), CDbl(num2)))
    End Function

    Public Shared Function Cos(ByVal num As BigFloat) As BigFloat
        Return BigFloat.Parse(System.Math.Cos(CDbl(num)))
    End Function

    Public Shared Function Cosh(ByVal num As BigFloat) As BigFloat
        Return BigFloat.Parse(System.Math.Cosh(CDbl(num)))
    End Function

    Public Shared Function Exp(ByVal num As BigFloat) As BigFloat
        Return BigFloat.Parse(System.Math.Exp(CDbl(num)))
    End Function

    Public Shared Function Log(ByVal num As BigFloat) As BigFloat
        Return BigFloat.Parse(System.Math.Log(CDbl(num)))
    End Function

    Public Shared Function Log(ByVal num As BigFloat, _
                               ByVal newBase As BigFloat) As BigFloat
        Return BigFloat.Parse(System.Math.Log(CDbl(num), CDbl(newBase)))
    End Function

    Public Shared Function Log10(ByVal num As BigFloat) As BigFloat
        Return BigFloat.Parse(System.Math.Log10(CDbl(num)))
    End Function

    Public Shared Function Sin(ByVal num As BigFloat) As BigFloat
        Return BigFloat.Parse(System.Math.Sin(CDbl(num)))
    End Function

    Public Shared Function Sinh(ByVal num As BigFloat) As BigFloat
        Return BigFloat.Parse(System.Math.Sinh(CDbl(num)))
    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 BigFloat) As BigFloat
        Return BigFloat.Parse(System.Math.Sqrt(CDbl(num)))
    End Function

    Public Shared Function Tan(ByVal num As BigFloat) As BigFloat
        Return BigFloat.Parse(System.Math.Tan(CDbl(num)))
    End Function

    Public Shared Function Tanh(ByVal num As BigFloat) As BigFloat
        Return BigFloat.Parse(System.Math.Tanh(CDbl(num)))
    End Function





    '--------------------------------------------------------------------------
    ' Métodos de instancia
    ' Si hay métodos de instancia y compartidos que se llaman igual
    ' estarán definidos con los compartidos.
    '--------------------------------------------------------------------------

    ''' <summary>
    ''' Devuelve una cadena con el BigNum actual
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks>
    ''' v.0.2 19/Oct/07
    ''' Si la parte decimal es cero, no se muestra
    ''' v.0.6 20/Oct/07
    ''' Si la parte entera es cero, mostrar el cero
    ''' </remarks>
    Public Overrides Function ToString() As String
        Dim i As Integer = Me.Decimales.ToString.Length - 1
        ' Si no tiene decimales
        ' devolver todo el número
        If i < 1 Then
            i = 1
            Me.Decimales = 10
            Me.Entero = Me.Entero * 10
        End If

        Dim s As String = Me.Entero.ToString
        Dim j As Integer = Len(s) - i

        ' Falla con la conversión de Double a BigFloat
        ' ya que los valores exponenciales no los controla bien
        ' Aunque con esto y con lo que hago en el Parse...
        ' parece que está bien
        If j < 0 Then
            j = i - Len(s) + 1
            s = New String("0"c, j) & s
            j = 0
        End If
        Dim bn As BigInt = Mid(s, j + 1)

        If bn.IsZero Then
            If j = 0 Then
                Return "0"
            End If
            Return Left(s, j)
        End If
        If j = 0 Then
            Return "0" & sepDec & Mid(s, j + 1)
        End If
        Return Left(s, j) & sepDec & Mid(s, j + 1)
    End Function


    '--------------------------------------------------------------------------
    ' Sobrecarga de operadores y conversiones
    '--------------------------------------------------------------------------

    '
    ' Conversiones
    '

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

    ''' <summary>
    ''' Convierte un BigFloat en un Double
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Narrowing Operator CType(ByVal num As BigFloat) As Double
        Return CDbl(num.ToString)
    End Operator

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

    ''' <summary>
    ''' Convierte un BigFloat en una cadena
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Widening Operator CType(ByVal num As BigFloat) As String
        ' Se devuelve lo mismo que ToString
        ' ya que se hace la comprobación de si se debe mostrar el decimal
        Return num.ToString
    End Operator

    ''' <summary>
    ''' Convierte una cadena en un BigFloat
    ''' La cadena solo debe contener números
    ''' Se admite indistintamente la coma o el punto
    ''' como separador decimal 
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Widening Operator CType(ByVal num As String) As BigFloat
        Return Parse(num)
    End Operator

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

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


    '
    ' Sobrecarga de operadores
    '

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

    ''' <summary>
    ''' Operador unario, niega el número
    ''' Si es positivo devuelve uno negativo
    ''' si es negativo lo devuelve como positivo
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Operator -(ByVal bn1 As BigFloat) As BigFloat
        Return BigFloat.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 BigFloat, ByVal bn2 As BigFloat) As BigFloat
        Return 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 BigFloat, ByVal bn2 As BigFloat) As BigFloat
        Return [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 BigFloat, ByVal bn2 As BigFloat) As BigFloat
        Return 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 BigFloat, ByVal bn2 As BigFloat) As BigFloat
        Return Div(bn1, bn2)
    End Operator

    ''' <summary>
    ''' División entera
    ''' Devuelve la parte entera de dividir los dos valores
    ''' después de redondearlo
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Operator \(ByVal bn1 As BigFloat, ByVal bn2 As BigFloat) As BigFloat
        Return Round(Div(bn1, bn2))
    End Operator

    ''' <summary>
    ''' Eleva el primer número a la potencia del segundo
    ''' (no funciona bien con potencias decimales)
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Operator ^(ByVal bn1 As BigFloat, ByVal bn2 As BigFloat) As BigFloat
        Return Pow(bn1, bn2)
    End Operator

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


    ''' <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 BigFloat, ByVal bn2 As BigFloat) As Boolean
        Return Iguales(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 BigFloat, ByVal bn2 As BigFloat) As Boolean
        Return Not Iguales(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 BigFloat, ByVal bn2 As BigFloat) As Boolean
        Dim i As Integer = Compare(bn1, bn2)
        Return i = -1
    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 BigFloat, ByVal bn2 As BigFloat) As Boolean
        Dim i As Integer = Compare(bn1, bn2)
        Return i = 1
    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 BigFloat, ByVal bn2 As BigFloat) As Boolean
        Dim i As Integer = Compare(bn1, bn2)
        Return i <= 0
    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 BigFloat, ByVal bn2 As BigFloat) As Boolean
        Dim i As Integer = Compare(bn1, bn2)
        Return i >= 0
    End Operator


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

    ''' <summary>
    ''' Devuelve True si el número es cero
    ''' </summary>
    ''' <param name="bn"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Operator IsFalse(ByVal bn As BigFloat) As Boolean
        Return 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