Bem-vindo(a), João da Rocha Labrego!

Seu trabalho é importante. Sou colaborador da Wikipédia. Espero que também goste de colaborar com esta enciclopédia, que dá a qualquer pessoa a possibilidade de ter livre acesso ao somatório de todo o conhecimento humano. Ajude-nos a melhorar e acrescentar informações. Obrigado por suas contribuições. Espero que goste daqui e decida ficar.

Aqui estão algumas páginas que podem ajudar:

Se precisar de ajuda, pergunte em minha página de discussão ou na página para tirar dúvidas. Pode também se inscrever no programa de tutoria e ser acompanhado(a) por um(a) editor(a) mais experiente. Por favor assine suas mensagens nas páginas de discussão usando quatro tiles (~~~~) ou o botão presente no alto da janela de edição; isso irá inserir automaticamente seu nome de usuário e a data. Guilherme Moura (discussão) 23h22min de 18 de fevereiro de 2015 (UTC)Responder

Testes em Logaritmo editar

  Boas vindas, e obrigado(a) por experimentar a Wikipédia. Seu teste na página Logaritmo funcionou, porém foi necessário revertê-lo ou excluí-lo. Motivo: o único local correto para testar as ferramentas de edição da Wikipédia é a página de testes. Por favor, consulte a página de boas-vindas para aprender mais a respeito de como contribuir com esta enciclopédia. Obrigado(a). Guilherme Moura (discussão) 23h22min de 18 de fevereiro de 2015 (UTC)Responder

Algoritmos Aritméticos editar

Tenho notado na Internet uma grande procura por algoritmos aritméticos, principalmente para trabalhar-se com números muito grandes que não cabem no escopo dos tipos numéricos disponíveis nas linguagens.

Como possuo uma coleção de algoritmos desenvolvidos e/ou coletados por mim na Internet, em função de uma biblioteca que estou desenvolvendo em C++ para trabalhar com números gigantes, gostaria disponibilizar esses mesmos algoritmos para as pessoas que deles necessitam.

Antes de mais nada, devo alerta-los de que usei o VBA para testar esses algoritmos e, por isso, disponibilizarei para vocês o código VBA para testes no EXCEL.

Não me delongarei em explicações sobre o código-fonte pois o entendimento ficará por conta do programado.

Defini o tipo numérico como BigInteger e, por isso, vocês deverão abrir uma planilha EXCEL e no VBA criar um módulo de classe com o nome BigInteger onde vocês copiarão o código-fonte abaixo na íntegra.

À medida em que eu for acrescentando novas coisas ou melhorando o código-fonte já existente, eu irei postando aqui para que vocês os utilizem.

No momento, creio que os programadores VBA mais avançados já conseguirão fazer alguma coisa com o código-fonte que ora disponibilizo.

  Option Explicit
  Option Base 1
  
  Private sign As Integer
  Private data() As LongLong
  Private length As Long
  Private physicalLength As Long
  
  Private Sub Class_Initialize()
  
     ToZero
     
  End Sub
  
  Private Sub Class_Terminate()
     'MsgBox "Created by João da Rocha Labrego"
  End Sub
  
  Friend Property Get Signal() As Integer
  
     Signal = sign
     
  End Property
  
  Friend Property Let Signal(ByVal value As Integer)
  
     sign = value
     
  End Property
  
  Friend Property Get Digit(ByVal index As Long) As LongLong
  
     Digit = data(index)
     
  End Property
  
  Friend Property Let Digit(ByVal index As Long, ByVal value As LongLong)
  
     data(index) = value
     
  End Property
  
  Friend Property Get GetLength() As Long
  
     GetLength = length
     
  End Property
  
  Public Function Parse(ByVal value As String) As String
  
     Dim i As Long, char As String
     
     Parse = vbNullString
     For i = 1 To Len(value)
         char = Mid(value, i, 1)
         If Not (char < "0" Or char > "9") Then
            If Not (char = "0" And Parse = vbNullString) Then
               Parse = Parse + char
            End If
         ElseIf char = "-" And Parse = vbNullString Then
            Parse = char
         End If
     Next
     
  End Function
  
  Friend Sub Resize(ByVal size As Long, Optional ByVal clearDigits As Boolean = False)
  
     Dim i As Long
     
     If size > physicalLength Then
        physicalLength = size + 50
        ReDim Preserve data(physicalLength)
     End If
     For i = IIf(clearDigits, 1, length + 1) To size
         data(i) = 0
     Next
     length = size
     
  End Sub
  
  Friend Sub ShiftRight(Optional times As Long = 1)
  
     Dim i As Long, j As Long
     
     If Not IsZero Then
        For i = 1 To times
            Resize length + 1
            For j = length To 2 Step -1
                data(j) = data(j - 1)
            Next
            data(j) = 0
        Next
     End If
     
  End Sub
  
  Public Sub SetValue(ByVal value As String)
  
     value = Parse(value)
     Valorize value
     
  End Sub
  
  Public Sub Valorize(ByVal value As String)
  
     Dim i As Long, j As Long, digitsCount As Long
     
     If value = vbNullString Then
        value = K_ZERO
     End If
     If Left(value, 1) = "-" Then
        sign = K_NEGATIVE
        value = Mid(value, 2)
     Else
        sign = K_POSITIVE
     End If
     digitsCount = Int(Len(value) / K_DIGIT_LENGTH) + IIf(Len(value) Mod K_DIGIT_LENGTH = 0, 0, 1)
     Resize digitsCount
     j = 1
     Do While value <> vbNullString
         data(j) = Val(Right(value, K_DIGIT_LENGTH))
         If Len(value) > K_DIGIT_LENGTH Then
            value = Left(value, Len(value) - K_DIGIT_LENGTH)
         Else
            value = vbNullString
         End If
         j = j + 1
     Loop
     
  End Sub
  
  Public Function GetValue() As String
  
     Dim i As Long
     
     GetValue = vbNullString
     For i = 1 To length - 1
         GetValue = Right(String(K_DIGIT_LENGTH, "0") + CStr(data(i)), K_DIGIT_LENGTH) + GetValue
     Next
     GetValue = IIf(sign = K_NEGATIVE, "-", "") + CStr(data(i)) + GetValue
     
  End Function
   
  Friend Sub Copy(ByRef value As BigInteger, Optional ByVal startIndex As Long = 1, Optional ByVal endIndex As Long = -1)
  
     Dim i As Long
     
     If endIndex = -1 Then
        endIndex = value.GetLength
     End If
     Resize endIndex - startIndex + 1
     sign = value.Signal
     For i = startIndex To endIndex
         data(i - startIndex + 1) = value.Digit(i)
     Next
     
  End Sub
  
  Friend Sub Append(ByRef value As BigInteger)
     Dim lastLength As Long, i As Long, j As Long
     
     lastLength = length
     j = value.GetLength
     If IsZero Then
        Resize value.GetLength
        lastLength = 0
     Else
        ShiftRight value.GetLength
     End If
     For i = length - lastLength To 1 Step -1
         data(i) = value.Digit(j)
         j = j - 1
     Next
  
  End Sub
  
  Public Sub ToZero()
  
     Resize 1
     sign = K_POSITIVE
     data(1) = 0
     
  End Sub
  
  Public Sub ToOne()
  
     Resize 1
     sign = K_POSITIVE
     data(1) = 1
     
  End Sub
  
  Public Function ToBigInteger(ByVal value As LongLong) As BigInteger
     
     Dim result As New BigInteger
  
     sign = IIf(value < 0, K_NEGATIVE, K_POSITIVE)
     Do
        result.Digit(result.GetLength) = value Mod K_NUMERIC_BASE
        value = Int(value / K_NUMERIC_BASE)
        If value > 0 Then
           result.Resize result.GetLength + 1
        Else
           Exit Do
        End If
     Loop
     
     Set ToBigInteger = result
     
  End Function
  
  Public Function IsZero() As Boolean
  
     IsZero = length = 1 And data(1) = 0
        
  End Function
  
  Public Function IsOne() As Boolean
  
     IsOne = length = 1 And data(1) = 1 And sign = K_POSITIVE
     
  End Function
  
  Public Function IsMinusOne() As Boolean
  
     IsOne = length = 1 And data(1) = 1 And sign = K_NEGATIVE
     
  End Function
  
  Public Function IsNegative() As Boolean
  
     IsNegative = sign = K_NEGATIVE
     
  End Function
  
  Public Function IsPositive() As Boolean
  
     IsPositive = sign = K_POSITIVE
     
  End Function
  
  Public Function IsEven() As Boolean
  
     IsEven = data(1) Mod 2 = 0
     
  End Function
  
  Public Function IsOdd() As Boolean
  
     IsOdd = data(1) Mod 2 = 1
     
  End Function
  
  Public Function Opposite() As BigInteger
     
     Dim result As New BigInteger
     
     result.Copy Me
     result.Signal = -result.Signal
     Set Opposite = result
  
  End Function
  
  Public Function Absolute() As BigInteger
     
     Dim result As New BigInteger
     
     result.Copy Me
     result.Signal = K_POSITIVE
     Set Absolute = result
  
  End Function
  
  Friend Sub Normalize()
  
     Dim i As Long
     
     For i = length To 1 Step -1
         If data(i) <> 0 Then
            Exit For
         End If
     Next
     If i < length Then
        If i > 0 Then
           Resize i
        Else
           ToZero
        End If
     End If
     
  End Sub
  
  Public Function Compare(ByRef value As BigInteger) As Integer
  
     Dim i As Long
     
     Compare = K_EQUAL
     If length < value.GetLength Then
        Compare = K_MINOR
     ElseIf length > value.GetLength Then
        Compare = K_MAJOR
     Else
        For i = length To 1 Step -1
            If data(i) < value.Digit(i) Then
               Compare = K_MINOR
               Exit For
            ElseIf data(i) > value.Digit(i) Then
               Compare = K_MAJOR
               Exit For
            End If
        Next
     End If
     
  End Function
  
  Public Function CompareDigit(ByVal value As LongLong) As Integer
  
     Dim i As Long
     
     Compare = K_EQUAL
     If length = 1 Then
        If data(1) < value Then
           Compare = K_MINOR
        ElseIf data(1) > value Then
           Compare = K_MAJOR
        End If
     ElseIf length > 1 Then
        Compare = K_MAJOR
     Else
        Compare = K_MINOR
     End If
     
  End Function
  
  Public Function Add(ByRef value As BigInteger) As BigInteger
  
     Dim addend1 As BigInteger, addend2 As BigInteger, result As New BigInteger, sum As LongLong, i As Long
  
     If sign = value.Signal Then
        If IsZero Then
           result.Copy value
        ElseIf value.IsZero Then
           result.Copy Me
        Else
           If length < value.GetLength Then
              addend1 = value
              addend2 = Me
           Else
              Set addend1 = Me
              Set addend2 = value
           End If
           sum = 0
           result.Resize addend1.GetLength
           For i = 1 To addend2.GetLength
               sum = sum + addend1.Digit(i) + addend2.Digit(i)
               result.Digit(i) = sum Mod K_NUMERIC_BASE
               sum = Int(sum / K_NUMERIC_BASE)
           Next
           For i = i To addend1.GetLength
               sum = sum + addend1.Digit(i)
               result.Digit(i) = sum Mod K_NUMERIC_BASE
               sum = Int(sum / K_NUMERIC_BASE)
           Next
           If sum > 0 Then
              result.Resize result.GetLength + 1
              result.Digit(i) = sum
           End If
        End If
        result.Normalize
        result.Signal = sign
     Else
        Set result = Subtract(value.Opposite)
     End If
     Set Add = result
     
  End Function
  
  Public Sub Increment()
  
     Dim i As Long
     
     If sign = K_NEGATIVE Then
        Set Me = Absolute.Decrement
        sign = K_NEGATIVE
     Else
        For i = 1 To length
            If data(i) = K_NUMERIC_BASE - 1 Then
               data(i) = 0
            Else
               data(i) = data(i) + 1
               Exit For
            End If
        Next
        If i > length Then
           Resize length + 1
           data(i) = 1
        End If
     End If
  
  End Sub
  
  Public Function Subtract(ByRef value As BigInteger) As BigInteger
  
     Dim minuend As BigInteger, subtrahend As BigInteger, result As New BigInteger, difference As LongLong, i As Long
     
     If sign = value.Signal Then
        If IsZero Then
           result.Copy value
        ElseIf value.IsZero Then
           result.Copy Me
        ElseIf Compare(value) = K_EQUAL Then
           result.ToZero
        Else
           If Compare(value) = K_MINOR Then
              Set minuend = value
              Set subtrahend = Me
           Else
              Set minuend = Me
              Set subtrahend = value
           End If
           result.Resize minuend.GetLength, True
           difference = 0
           For i = 1 To subtrahend.GetLength
               difference = K_NUMERIC_BASE + minuend.Digit(i) - subtrahend.Digit(i) - difference
               result.Digit(i) = difference Mod K_NUMERIC_BASE
               difference = IIf(difference < K_NUMERIC_BASE, 1, 0)
           Next
           For i = i To minuend.GetLength
               difference = K_NUMERIC_BASE + minuend.Digit(i) - difference
               result.Digit(i) = difference Mod K_NUMERIC_BASE
               difference = IIf(difference < K_NUMERIC_BASE, 1, 0)
           Next
           result.Signal = minuend.Signal
           result.Normalize
        End If
     Else
        Set result = Add(value.Opposite)
     End If
     Set Subtract = result
        
  End Function
  
  Public Sub Decrement()
  
     Dim i As Long
     
     If sign = K_NEGATIVE Then
        Set Me = Absolute.Increment
        sign = K_NEGATIVE
     Else
        For i = 1 To length
            If data(i) = 0 Then
               data(i) = K_NUMERIC_BASE - 1
            Else
               data(i) = data(i) - 1
               Exit For
            End If
        Next
     End If
     
  End Sub
  
  Public Function Multiply(ByRef value As BigInteger) As BigInteger
  
     Dim i As Long, j As Long, k As Long, result As New BigInteger, product As LongLong
     
     If IsZero Or value.IsZero Then
        result.ToZero
     ElseIf IsOne Then
        result.Copy value
     ElseIf value.IsOne Then
        result.Copy Me
     Else
        result.Resize length + value.GetLength, True
        For i = 1 To length
            k = i
            product = 0
            For j = 1 To value.GetLength
                product = product + data(i) * value.Digit(j) + result.Digit(k)
                result.Digit(k) = product Mod K_NUMERIC_BASE
                product = Int(product / K_NUMERIC_BASE)
                k = k + 1
            Next
            result.Digit(k) = product
        Next
        result.Normalize
     End If
     result.Signal = sign * value.Signal
     Set Multiply = result
     
  End Function
  
  Public Function MultiplyByDigit(ByVal value As LongLong) As BigInteger
     
     Dim result As New BigInteger, product, i As Long
     
     If IsZero Or value = 0 Then
        result.ToZero
     ElseIf IsOne Then
        result = ToBigInteger(value)
     ElseIf value = 1 Then
        result.Copy Me
     Else
        value = value Mod K_NUMERIC_BASE
        result.Resize length + 1, True
        product = 0
        For i = 1 To length
            product = product + data(i) * value
            result.Digit(i) = product Mod K_NUMERIC_BASE
            product = Int(product / K_NUMERIC_BASE)
        Next
        If product > 0 Then
           result.Digit(result.GetLength) = product
        End If
        result.Normalize
     End If
     result.Signal = sign * IIf(value < 0, K_NEGATIVE, K_POSITIVE)
     Set MultiplyByDigit = result
     
  End Function
  
  Public Function Divide(ByRef value As BigInteger, Optional ByRef remainder As BigInteger = Nothing) As BigInteger
     Dim dividend As New BigInteger, product As New BigInteger, result As New BigInteger, minQuotient As LongLong, _
         maxQuotient As LongLong, quotient As LongLong, comparison As Integer, haveQuotient As Boolean, i As Long
     
     If value.IsZero Then
        Err.Raise 1000, Nothing, "Divisor is zero."
     End If
     Set remainder = New BigInteger
     If IsZero Then
        result.ToZero
        remainder.ToZero
     ElseIf value.IsOne Then
        result.Copy Me
        remainder.ToZero
     Else
        comparison = Compare(value)
        If comparison = K_MINOR Then
           result.ToZero
           remainder.Copy Me
        ElseIf comparison = K_EQUAL Then
           result.ToOne
           remainder.ToZero
        Else
           haveQuotient = False
           For i = length To 1 Step -1
               dividend.ShiftRight
               dividend.Digit(1) = data(i)
               comparison = dividend.Compare(value)
               If comparison = K_MINOR Then
                  If haveQuotient Then
                     result.ShiftRight
                  End If
               ElseIf comparison = K_EQUAL Then
                  result.ShiftRight
                  result.Digit(result.GetLength) = 1
                  haveQuotient = True
               Else
                  result.ShiftRight
                  minQuotient = 0
                  maxQuotient = CLng(K_NUMERIC_BASE) - 1
                  Do While minQuotient <= maxQuotient
                     quotient = Int((minQuotient + maxQuotient) / 2)
                     Set product = value.MultiplyByDigit(quotient)
                     comparison = product.Compare(dividend)
                     If comparison = K_EQUAL Then
                        maxQuotient = quotient
                        Exit For
                     End If
                     If comparison = K_MINOR Then
                        minQuotient = quotient + 1
                     Else
                        maxQuotient = quotient - 1
                     End If
                  Loop
                  If quotient <> maxQuotient Then
                     Set product = value.MultiplyByDigit(maxQuotient)
                  End If
                  result.Digit(1) = maxQuotient
                  Set dividend = dividend.Subtract(product)
                  haveQuotient = True
               End If
           Next
           result.Normalize
           remainder.Copy dividend
        End If
     End If
     result.Signal = sign * value.Signal
     Set Divide = result
     
  End Function
  
  Public Function DivideByDigit(ByVal value As LongLong, Optional ByRef remainder As BigInteger = Nothing) As BigInteger
  
     Dim result As New BigInteger, dividend As LongLong, quotient As LongLong, i As Long, j As Long, haveQuotient As Boolean
     
     If value = 0 Then
        Err.Raise 1000, Nothing, "Divisor is zero."
     End If
     Set remainder = New BigInteger
     If IsZero Then
        result.ToZero
        remainder.ToZero
     ElseIf value = 1 Then
        result.Copy Me
        remainder.ToZero
     Else
        comparison = CompareDigit(value)
        If comparison = K_MINOR Then
           result.ToZero
           remainder.Copy Me
        ElseIf comparison = K_EQUAL Then
           result.ToOne
           remainder.ToZero
        Else
           value = value Mod K_NUMERIC_BASE
           dividend = 0
           result.Resize length - IIf(value > data(length), 1, 0), True
           j = result.GetLength
           For i = length To 1 Step -1
               dividend = dividend * K_NUMERIC_BASE + data(i)
               If dividend >= value Then
                  quotient = Int(dividend / value)
                  result.Digit(j) = quotient
                  j = j - 1
                  dividend = dividend - quotient * value
                  haveQuotient = True
               ElseIf haveQuotient Then
                   result.Digit(j) = 0
                   j = j - 1
               End If
           Next
           remainder.Copy ToBigInteger(dividend)
           result.Normalize
        End If
     End If
     result.Signal = sign * IIf(value < 0, K_NEGATIVE, K_POSITIVE)
     Set DivideByDigit = result
     
  End Function
  
  Public Function Power(ByVal exponent As LongLong) As BigInteger
     Dim base As New BigInteger, result As New BigInteger
     
     exponent = Abs(exponent)
     If exponent = 0 Then
        result.ToOne
     ElseIf exponent = 1 Then
        result.Copy Me
     Else
        base.Copy Me
        result.ToOne
        If exponent > 0 Then
           Do While exponent > 1
              If exponent Mod 2 = 1 Then
                 Set result = result.Multiply(base)
                 If exponent = 1 Then
                    Exit Do
                 End If
              End If
              Set base = base.Multiply(base)
              exponent = Int(exponent / 2)
           Loop
           Set result = result.Multiply(base)
        End If
     End If
     result.Signal = IIf(exponent Mod 2 = 0, K_POSITIVE, Signal)
     Set Power = result
  End Function
  
  Public Function Root(ByVal degree As Long, Optional remainder As BigInteger = Nothing) As BigInteger
  
     Dim radicand As New BigInteger, potency As New BigInteger, result As New BigInteger, buffer As New BigInteger, _
         radix As LongLong, minRadix As LongLong, maxRadix As LongLong, groupLength As Long, i As Long, _
         comparison As Integer, coeficient As New BigInteger
            
     degree = Abs(degree)
     Set remainder = New BigInteger
     If degree = 0 Then
        Err.Raise 1000, Nothing, "Degree is zero."
     End If
     If degree Mod 2 = 0 And IsNegative Then
        Err.Raise 1000, Nothing, "Even degree with negative radicand."
     End If
     If degree = 1 Or IsOne Or IsZero Then
        result.Copy Me
        remainder.ToZero
     Else
        groupLength = length Mod degree
        groupLength = IIf(groupLength = 0, degree, groupLength)
        i = length
        minRadix = 1
        radix = 0
        coeficient.Valorize CStr(K_NUMERIC_BASE)
        Set coeficient = coeficient.Power(degree - 1)
        Set coeficient = coeficient.MultiplyByDigit(degree)
        maxRadix = data(1)
        remainder.ToZero
        Do While i > 1
           i = i - groupLength
           buffer.Copy Me, i + 1, i + groupLength
           radicand.Append buffer
           remainder.Append radicand
           groupLength = degree
           result.ShiftRight
           Do While minRadix <= maxRadix
              radix = Int((minRadix + maxRadix) / 2)
              result.Digit(1) = radix
              Set potency = result.Power(degree)
              comparison = potency.Compare(radicand)
              If comparison = K_EQUAL Then
                 maxRadix = radix
                 Exit Do
              End If
              If comparison = K_MINOR Then
                 minRadix = radix + 1
              Else
                 maxRadix = radix - 1
              End If
           Loop
           remainder.Copy Subtract(potency)
           result.Digit(1) = maxRadix
           minRadix = 0
        Loop
        result.Normalize
        If result.Digit(1) <> radix Then
           Set potency = result.Power(degree)
        End If
        remainder.Copy Subtract(potency)
     End If
     result.Signal = sign
     Set Root = result
     
  End Function

João da Rocha Labrego (discussão) 01h33min de 21 de fevereiro de 2015 (UTC)Responder