11111010111 1010 1011

Programar por Programar


¿Te gusta programar?
Inicio


Código fuente de BigFloat.vb

Estructura en Visual Basic 2005 que usa BigNum_ltm.dll y BigNum.vb


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


 

Este es el código fuente de BigFloat, esta estructura usa BigNum para hacer los cálculos y demás cosas que "intenta" hacer.


Código fuente de BigFloat
'------------------------------------------------------------------------------
' BigFloat                                                          (12/Oct/07)
' Estructura para trabajar con números grandes con decimales
'
' Basado en BigNum
' Estructura para trabajar con números enteros de alta precisión.
'
' La DLL BigNum_ltm.dll debe estar en el mismo directorio o en el PATH.
'
' ©Guillermo 'guille' Som, 2006-2007
'
' Para usar esta estructura
' Dim a As BigFloat
' a = BigFloat.Parse("...")
'------------------------------------------------------------------------------
Option Explicit On
Option Strict On

Imports System
Imports Microsoft.VisualBasic

Imports System.Text
Imports System.Threading

''' <summary>
''' Estructura para manejar números de gran preción de coma flotante
''' </summary>
''' <remarks>
''' Iniciado: 12/Oct/2007
''' Revisado: 22/Oct/2007
''' </remarks>
Public Structure BigFloat
    Implements IComparable

    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

    Public Entero As BigNum
    Public Decimales As BigNum

    Private Shared ReadOnly bigFloatZero As BigFloat
    Private Shared ReadOnly bigFloatOne As BigFloat
    Private Shared ReadOnly bigFloatTwo As BigFloat

    Private Shared ReadOnly sepDec As String

    Shared Sub New()
        sepDec = Thread.CurrentThread.CurrentCulture. _
                        NumberFormat.CurrencyDecimalSeparator

        bigFloatZero = New BigFloat(BigNum.Zero)
        bigFloatOne = New BigFloat(BigNum.One)
        bigFloatTwo = New BigFloat(BigNum.Two)

    End Sub

    Public Sub New(ByVal ent As BigNum, ByVal dec As BigNum)
        Entero = ent
        If dec.IsZero Then
            dec = bigFloatOne ' BigNum.One
        End If
        Decimales = dec
    End Sub

    Public Sub New(ByVal ent As BigNum)
        Entero = ent
        ' Hay que usr BigNum.One porque el valor
        ' no se habrá asignado en el constructor
        ' compartido la primera vez que se llame 
        ' a este constuctor
        Decimales = BigNum.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 BigNum
        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 BigNum = "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 BigNum en BigFloat
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Parse(ByVal num As BigNum) As BigFloat
        Return New BigFloat(num)
    End Function

    ''' <summary>
    ''' Convierte un BigFloat en un BigNum
    ''' </summary>
    ''' <param name="num"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function ToBigNum(ByVal num As BigFloat) As BigNum
        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 BigNum(s)
    End Function



    ''' <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 cero
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function Zero() As BigFloat
        'Return New BigFloat(BigNum.BigNumZero)
        Return bigFloatZero
    End Function

    ''' <summary>
    ''' Devuelve un BigFloat con valor 1
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function One() As BigFloat
        'Return New BigFloat(1)
        Return bigFloatOne
    End Function

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



    ''' <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.used = 0 'AndAlso n1.Decimales.used = 0)
    End Function

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


    ''' <summary>
    ''' Convierte el BigNum 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 BigNum.ToInt32(Me.Entero)
    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 BigNum = BigNum.BigNumMul(n1.Entero, n2.Entero)
        Dim bn2 As BigNum = BigNum.BigNumMul(n1.Decimales, n2.Decimales)

        Return New BigFloat(bn1, bn2)
    End Function

    Public Const MaxDecimalesMaxValue As Integer = 1000
    Public Const MaxDecimalesMinValue As Integer = 0
    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>
    ''' 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 BigNum = BigNum.BigNumMul(n1.Entero, n2.Decimales)
        Dim bn2 As BigNum = BigNum.BigNumMul(n2.Entero, n1.Decimales)

        Return DivBigNumToFloat(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>
    ''' Divide dos BigNum y devuelve el resultado como BigFloat
    ''' </summary>
    ''' <param name="bn1"></param>
    ''' <param name="bn2"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Shared Function DivBigNumToFloat(ByVal bn1 As BigNum, _
                                             ByVal bn2 As BigNum) As BigFloat
        Dim bn3 As BigNum = BigNum.Zero
        Dim bn4 As BigNum = BigNum.BigNumDiv(bn1, bn2, bn3)

        Dim s3 As String = bn3

        Dim sb As New System.Text.StringBuilder
        Dim n3 As BigNum = BigNum.Zero

        For j As Integer = 1 To MaxDecimales
            bn1 = bn4 * 10
            bn4 = BigNum.BigNumDiv(bn1, bn2, n3)
            sb.Append(BigNum.BigNumAbs(n3).ToString)
        Next

        Dim s4 As String = sb.ToString().TrimEnd("0".ToCharArray)
        Dim bn5 As BigNum = (s3 & s4)
        Dim bi As BigNum = ("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 BigNum = BigNum.BigNumAdd(n1.Entero * n2.Decimales, _
                                             n2.Entero * n1.Decimales)
        Dim bn2 As BigNum = BigNum.Mul(n1.Decimales, n2.Decimales)

        Return DivBigNumToFloat(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 BigNum = BigNum.BigNumSub(n1.Entero * n2.Decimales, _
                                             n2.Entero * n1.Decimales)
        Dim bn2 As BigNum = BigNum.Mul(n1.Decimales, n2.Decimales)

        Return DivBigNumToFloat(bn1, bn2)
    End Function


    ''' <summary>
    ''' Decrementa uno al BigNum 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 BigNum = 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(System.Math.Pow(CDbl(bn1.Entero), d2), _
                            System.Math.Pow(CDbl(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)
    '

    ''' <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
        'Return BigFloat.Parse(System.Math.Abs(CDbl(num)))
        If num < BigFloat.Zero Then
            Return (num * -BigFloat.One)
        Else
            Return num
        End If
    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

    ''' <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

    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

    ''' <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

    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

    ''' <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

    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

    ''' <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 BigNum = BigFloat.ToBigNum(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


    '--------------------------------------------------------------------------
    ' 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 BigNum = 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



    ''' <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 = BigNum.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 entero BigInt
    ''' </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

    Public Shared Function Neg(ByVal num1 As BigFloat) As BigFloat
        num1.Entero = BigNum.BigNumNeg(num1.Entero)
        Return num1
    End Function


    '--------------------------------------------------------------------------
    ' Sobrecarga de operadores
    '--------------------------------------------------------------------------

    Public Shared Widening Operator CType(ByVal num As Double) As BigFloat
        Return Parse(num)
    End Operator

    Public Shared Narrowing Operator CType(ByVal num As BigFloat) As Double
        Return CDbl(num.ToString)
    End Operator

    Public Shared Narrowing Operator CType(ByVal num As BigFloat) As Integer
        Return ToInt32(num)
    End Operator

    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

    Public Shared Widening Operator CType(ByVal num As String) As BigFloat
        Return Parse(num)
    End Operator

    Public Shared Widening Operator CType(ByVal num As BigNum) As BigFloat
        Return Parse(num)
    End Operator

    Public Shared Widening Operator CType(ByVal num As BigFloat) As BigNum
        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 BigNum(s)
    End Operator


    Public Shared Operator +(ByVal bn1 As BigFloat) As BigFloat
        Return bn1
    End Operator

    Public Shared Operator -(ByVal bn1 As BigFloat) As BigFloat
        Return BigFloat.Neg(bn1)
    End Operator


    Public Shared Operator +(ByVal bn1 As BigFloat, ByVal bn2 As BigFloat) As BigFloat
        Return Add(bn1, bn2)
    End Operator

    Public Shared Operator -(ByVal bn1 As BigFloat, ByVal bn2 As BigFloat) As BigFloat
        Return [Sub](bn1, bn2)
    End Operator

    Public Shared Operator *(ByVal bn1 As BigFloat, ByVal bn2 As BigFloat) As BigFloat
        Return Mul(bn1, bn2)
    End Operator

    Public Shared Operator /(ByVal bn1 As BigFloat, ByVal bn2 As BigFloat) As BigFloat
        Return Div(bn1, bn2)
    End Operator

    Public Shared Operator \(ByVal bn1 As BigFloat, ByVal bn2 As BigFloat) As BigFloat
        Return Div(bn1, bn2)
    End Operator

    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



    Public Shared Operator =(ByVal bn1 As BigFloat, ByVal bn2 As BigFloat) As Boolean
        Return Iguales(bn1, bn2)
    End Operator

    Public Shared Operator <>(ByVal bn1 As BigFloat, ByVal bn2 As BigFloat) As Boolean
        Return Not Iguales(bn1, bn2)
    End Operator

    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

    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

    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

    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


    Public Shared Operator IsTrue(ByVal bn As BigFloat) As Boolean
        Return Not IsZero(bn)
    End Operator

    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