calculadora por jerarquia ()*/+- ...C#...

Iniciado por clipto, 30 Julio 2009, 05:41 AM

0 Miembros y 2 Visitantes están viendo este tema.

clipto

bueno he estado pendiente de estos post porque me gustaria emplear las pilas (para casos como este u otros) pero buscando en internet encontre esto:



pero mi duda consiste esque ese ejemplo muesta que toma desde el ultimo valor y va calculado, pero mi duda consiste enque ahi esta organizado pero en una cadena desorganizada por lo menos la siguiente:
((5*8)-2)+5-7

donde segun las pilas empesaria por el ultimo valor, pero por jerarquia deberia empezar por 5*8 desde los primeros valores hasta el ultimo; y expresiones mas complejas como la dicha por raul338
6 + (8 + 3) - [6 * (3 + 2) + 5] * (2 * 10 / 5) + (5 * ((2 * 6) + 2)

entonces ¿es necesario que esten organizadas las expresiones para que las pilas funcionen?

h0oke

Creo que uno no siempre comienza con el último valor, ya que hay métodos en listas enlazadas para encontrar un elemento el cual "analizar" o en este caso, resolver.

Nuevamente,disculpas si me equivoco..

raul338

La ayudita de clipto me sirvio, y creo encontrar el error jeje.... y estuve pensando, estamos mal en no tomar en cuenta los parentesis como deberian ser tomados!!!!
Nosotros en matematicas que hacemos si vemos un parentesis, corchetes o llaves???? Primero resolvemos lo que esta dentro y despues continuamos. Asi que, en la pila podria quedar asi
6 + (8 + 3) - (6 * (3 + 2) + 5) * (2 * 10 / 5) + (5 * ((2 * 6) + 2)

Citar1: +6
2: (8 + 3)
3: - (6 * (3 + 2) + 5) * (2 * 10 / 5)
4: (5 * ((2 * 6) + 2)

luego, con un parser que estoy creando, deberia crearse otra pila, asi

Citar1: +6
2: // Una pila dentro de otra pila, medio lioso, pero asi se me ocurrio xD
   2.1: +8
   2.2: +3
3:
   3.1: +6 * (3 + 2) + 5
   3.2: *+(2 * 10 / 5)
4:
   4.1: +5 * (2 * 6)
   4.2: +2

3º vuelta:

Citar1: +6
2: +11
3:
   3.1:
       3.1.1: +6 * (3+2)
       3.1.2: +5
   3.2: *
       3.2.1: +2
       3.2.2: *+10
       3.2.3: /+5
4:
   4.1: +5 * (2 * 6)
       4.1.1: +5
       4.1.2: * (2 * 6)
   4.2: +2
y como siga....
Se entiende lo que quiero hacer??? Ya casi tengo mi expresion regular para detectar ecuaciones ^^, lo que si me va a hacer un poco dificil el tema de la separacion (las vueltas), usare recursividad (no me digan que es mala, eso era en epocas cuando todos tenian 64 mb ram, ahora que todos tienen 512 o mas¿No tienen suficiente memoria para gastarla? :xD)

h0oke

Raul, en wikipedia también había un ejemplo, no lo quice poner, pero en esa página está toda la info acerca de pilas.

Éxitos con tu trabajo.

raul338

#24
 :o Lo Logre!!!  ;D :P

Costo un poco.... lo hice ayer (domingo a la tarde jeje) y tenia un problema con los numeros negativos que hoy ya resolvi....aunque no he probado todo tipo de operaciones xD. Eso si....solo soporta los siguentes operadores: + * - / ( )
No soprota potenciación, ahora intentare agregarle esa funcion jeje
Como funciona?? (rapidamente explicado) Divide en terminos, si el termino es numerico suma o resta, si es una multiplicacion o division y/o con parentesis se analiza otra vez (usando recursividad).
No esta totalmente testeado, es MUY posible que encuentre algun error jeje, sigo trabajando en esta calcu

Como usarlo?? Simple, llaman a Eval("5+3*9") por ejemplo y esta le retorna un valor double (en caso de que haya decimales)....


que no se diga mas..aca el codigo  :xD
Código (vbnet) [Seleccionar]
Imports System.Text.RegularExpressions

Module Module1

    Sub Main()
        Dim opcion As String = ""
        Console.WriteLine("Ingrese una operacion combinada o 'end' para salir")

        Do
            opcion = Console.ReadLine()

            If opcion = "end" Then Exit Do

            Try
                Console.WriteLine("Resultado: " & Eval(opcion).ToString("N"))
            Catch ex As Exception
                Console.ForegroundColor = ConsoleColor.White
                Console.WriteLine("Error: " & ex.Message)
                Console.ForegroundColor = ConsoleColor.Gray
            End Try
        Loop
    End Sub

    Public Function Eval(ByVal operacion As String) As Double
        Dim resp As Double = 0D
        Dim temp As Double = 0D

        operacion = operacion.Replace(" ", "")
        operacion = operacion.Replace(".", ",")

        Dim RegexObj As New Regex( _
            "(?<Termino>[+\-]?  (?: \d [\d,*/]* | \( [\d,+\-*/]* \) (?: [*/] \d | [*/] \( [\d,+\-*/]* \) )* ) )", _
            RegexOptions.IgnorePatternWhitespace)
        If RegexObj.IsMatch(operacion) Then
            Dim MatchResults As MatchCollection = RegexObj.Matches(operacion)
            Dim MatchResult As Match = MatchResults(0)
            Dim termino As String
            For i As Int32 = 0 To MatchResults.Count - 1
                termino = MatchResult.Groups("Termino").Value
                If IsNumeric(termino) Then
                    temp = Double.Parse(termino)
                Else
                    ' No podemos pasarle +(5+5)*2 porque lo tomaria como termino y entraria en un bucle infinito
                    ' asi que le extraemos el signo, por defecto le ponemos como positivo y despues le volvemos al
                    ' signo que debe tener
                    Dim signo As Integer = 1

                    If termino.Substring(0, 1) = "-" Then
                        signo = -1
                        termino = termino.Substring(1)
                    ElseIf termino.Substring(0, 1) = "+" Then
                        signo = 1
                        termino = termino.Substring(1)
                    End If
                    temp = ResolverTermino(termino)

                    temp *= signo ' Multiplicamos por -1 para cambiar el signo, por 1 para mantenerlo igual
                End If

                resp += temp
                MatchResult = MatchResult.NextMatch()
            Next

            Return resp
        Else
            Throw New Exception("La operacion no pudo ser reconocida")
        End If
    End Function

    Function ResolverTermino(ByVal Termino As String) As Double
        Dim resp As Double = 0D
        Dim temp As Double = 0D

        Dim RegexObj As New Regex("(?<Termino> [\+\-]?\( .* \) | [\*\/] \d*\,?\d* | [\+\-]? \d*\,?\d* )", RegexOptions.IgnorePatternWhitespace)

        If RegexObj.IsMatch(Termino) Then

            Dim MatchResults As MatchCollection = RegexObj.Matches(Termino)
            Dim MatchResult As Match = MatchResults(0)
            Dim subTermino As String
            For I As Int32 = 0 To MatchResults.Count - 2
                subTermino = MatchResult.Groups("Termino").Value
                If IsNumeric(subTermino) Then
                    resp = Double.Parse(subTermino)
                Else
                    Select Case subTermino.Substring(0, 1)
                        Case "*"
                            temp = Double.Parse(subTermino.Substring(1))
                            resp *= temp
                        Case "/"
                            temp = Double.Parse(subTermino.Substring(1))
                            resp /= temp
                        Case Else
                            resp = Eval(Regex.Match(subTermino, "\((?<Operacion>.*)\)").Groups("Operacion").Value)
                    End Select
                End If
                MatchResult = MatchResult.NextMatch
            Next
            Return resp
        Else
            Throw New Exception("Parte de la operacion no pudo ser reconocida")
        End If
    End Function
End Module


Esta en vb.net.....pero es facilmente convertible, cuando este bien terminado y sin bugs (por ejemplo, ahora no se puede poner "((1+2)*3)*4)" porque lo rompes jajaja) lo convertire a C# con mis propias manos xD

Cualquier ayuda se agradece  ;D

EDIT: Arreglado el tema de los espacios, y el punto (que es una coma en realidad)

h0oke

Excelente  ;-)

Apenas tenga un tiempito le hecharé un ojo.

Un saludo!