elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Tutorial básico de Quickjs


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderadores: Eternal Idol, Littlehorse, K-YreX)
| | |-+  Ayuda Calculadora
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: Ayuda Calculadora  (Leído 2,742 veces)
vhh70

Desconectado Desconectado

Mensajes: 6


Ver Perfil
Ayuda Calculadora
« en: 1 Junio 2018, 23:01 pm »

Buen dia, espero puedan ayudarme estoy haciendo un programa de Notacion Polaca, mi problema es que me hace falta una funcion que al leer la cadena esta funcion realice la operacion (como una calculadora).
Por ejemplo:
(2+6)*10=80

Tengo esta funcion pero solo es para numeros de un digito, tengo pensado usar apuntadores pero no se como.

Código:
//MOSTRAMOS EL RESUTALTADO DE LA OPERACION
void resultado(char cadena[100]){
char operador, operandoX, operandoY; //VARIABLES PARA PODER OPERAR
int resultado, pilaResultado[100]; //PILA PARA GUARDAR LOS RESULTADOS

printf("\n\nSolucion");

for(int i = 0, j = -1; i < strlen(cadena); i++){ //RECORREMOS LA CADENA
if((((int(cadena[i])) > 47) && ((int(cadena[i])) < 58))){ //SI SE LEE UN NUMERO ENTONCES SE AGREGA A LA PILA DE RESULTADOS
j++; //AUMETAMOS EL TOPE DE LA PILA
pilaResultado[j] = (int)cadena[i] - 48; //SE CASTEA EL CARECTER Y SE LE RESTAN 48 PARA PODER GUARDAR EL NUMERO QUE SE LEE COMO CARACTER
}else if(cadena[i] == '!'){ //SI SE LEE UNA OPERACION DE NEGACION
operandoX = pilaResultado[j]; //SE TOMA EL ULTIMO VALOR DE LA PILA DE OPERACION
resultado = operandoX * (-1); //SE MULTIPLICA POR -1
pilaResultado[j] = resultado; //SE GURADA EL RESULTADO EN EL TOPE DE LA PILA DE RESULTADOS
printf("\n\t!%i = %i", operandoX, resultado);
}else if(cadena[i] == '+'){ //SI SE LEE UNA OPERACION DE SUMA
operandoX = pilaResultado[j]; //SE EXTRAE EL TOPE DE LA PILA Y SE GUARDA EN OPERANDOX
j--; //SE DISMINUYE EL TOPE DE LA PILA
operandoY = pilaResultado[j]; //SE EXTRAE EL TOPE DE LA PILA Y SE GUARDA EN OPERANDOY
resultado = operandoX + operandoY; //RE OPERAN LAS VARIABLES OPERANDOX Y OPERANDOY
pilaResultado[j] = (int)resultado; //SE GUARDA EL RESULTADO
printf("\n\t%d + %i = %i", operandoY, operandoX, resultado);
}else if(cadena[i] == '-'){ //EN CASO DE QUE SE LEA UNA OPERACION DE RESTA
operandoX = pilaResultado[j];
j--;
operandoY = pilaResultado[j];
resultado = operandoY - operandoX;
pilaResultado[j] = resultado;
printf("\n\t%d - %i = %i", operandoY, operandoX, resultado);
}else if(cadena[i] == '*'){ //EN CASO DE QUE SE LEA UNA OPERACION DE MULTIPLICACION
operandoX = pilaResultado[j];
j--;
operandoY = pilaResultado[j];
resultado = operandoY * operandoX;
pilaResultado[j] = resultado;
printf("\n\t%d * %i = %i", operandoY, operandoX, resultado);
}else if(cadena[i] == '/'){ //EN CASO DE QUE SE LEA UNA OPERACION DE DIVISION
operandoX = pilaResultado[j];
j--;
operandoY = pilaResultado[j];
if(operandoX == 0)
resultado = 0;
else
resultado = operandoY / operandoX;
pilaResultado[j] = resultado;
printf("\n\t%d / %i = %i", operandoY, operandoX, resultado);
}else if(cadena[i] == '^'){ //EN CASO DE QUE SE LEA UNA OPERACION DE EXPONENTE
operandoX = pilaResultado[j];
j--;
operandoY = pilaResultado[j];
resultado = pow(operandoY,operandoX);
pilaResultado[j] = resultado;
printf("\n\t%d ^ %i = %i", operandoY, operandoX, resultado);
}
}
printf("\nResultado: %i", pilaResultado[0]); //SE MUESTRA EL RESULTADO FINAL
}


Nota:No puedo subir el codigo de notacion porque aun no me califican pero en cuanto me califique lo subire.


En línea

SrMcLister

Desconectado Desconectado

Mensajes: 35



Ver Perfil
Re: Ayuda Calculadora
« Respuesta #1 en: 2 Junio 2018, 00:31 am »

Buenas!
Por favor, justifica mejor tu código, leer ese maraña de letras es imposible


En línea

Código
  1. return((u.areHappy() && u.knowIt()) ? u.clapYourHands() : u.goFuckYourself());
vhh70

Desconectado Desconectado

Mensajes: 6


Ver Perfil
Re: Ayuda Calculadora
« Respuesta #2 en: 2 Junio 2018, 00:43 am »

Este es solo para una cifra, lo que necesito es que reciva mas de una cifra pero si lo hago con este necesiraria mas arreglos
Código:
/
void resultado(char cadena[100]){
char operador, operandoX, operandoY;
int resultado, pilaResultado[100];

printf("\n\nSolucion");

for(int i = 0, j = -1; i < strlen(cadena); i++){
if((((int(cadena[i])) > 47) && ((int(cadena[i])) < 58))){
j++; //AUMETAMOS EL TOPE DE LA PILA
pilaResultado[j] = (int)cadena[i] - 48;
}else if(cadena[i] == '!'){
operandoX = pilaResultado[j];
resultado = operandoX * (-1);
pilaResultado[j] = resultado;
printf("\n\t!%i = %i", operandoX, resultado);
}else if(cadena[i] == '+'){
operandoX = pilaResultado[j];
j--;
operandoY = pilaResultado[j];
resultado = operandoX + operandoY;
pilaResultado[j] = (int)resultado;
printf("\n\t%d + %i = %i", operandoY, operandoX, resultado);
}else if(cadena[i] == '-'){
operandoX = pilaResultado[j];
j--;
operandoY = pilaResultado[j];
resultado = operandoY - operandoX;
pilaResultado[j] = resultado;
printf("\n\t%d - %i = %i", operandoY, operandoX, resultado);
}else if(cadena[i] == '*'){
operandoX = pilaResultado[j];
j--;
operandoY = pilaResultado[j];
resultado = operandoY * operandoX;
pilaResultado[j] = resultado;
printf("\n\t%d * %i = %i", operandoY, operandoX, resultado);
}else if(cadena[i] == '/'){
operandoX = pilaResultado[j];
j--;
operandoY = pilaResultado[j];
if(operandoX == 0)
resultado = 0;
else
resultado = operandoY / operandoX;
pilaResultado[j] = resultado;
printf("\n\t%d / %i = %i", operandoY, operandoX, resultado);
}else if(cadena[i] == '^'){
operandoX = pilaResultado[j];
j--;
operandoY = pilaResultado[j];
resultado = pow(operandoY,operandoX);
pilaResultado[j] = resultado;
printf("\n\t%d ^ %i = %i", operandoY, operandoX, resultado);
}
}
printf("\nResultado: %i", pilaResultado[0]);
}
En línea

Serapis
Colaborador
***
Desconectado Desconectado

Mensajes: 3.391


Ver Perfil
Re: Ayuda Calculadora
« Respuesta #3 en: 2 Junio 2018, 03:54 am »

.... quedó duplicado, al tratar de modificarlo.
« Última modificación: 2 Junio 2018, 04:05 am por NEBIRE » En línea

Serapis
Colaborador
***
Desconectado Desconectado

Mensajes: 3.391


Ver Perfil
Re: Ayuda Calculadora
« Respuesta #4 en: 2 Junio 2018, 04:04 am »

Es que has ido a lo fácil... operar con bytes (chars), resulta cómodo...

Bueno, la solución es que precisas una pequeña función que es un analizador léxico (en inglés lo suelen llamar scanner)... para ir leyendo la cadena de entrada y reconocer los números...

Te aproximo al resultado de lo que necesitas...


Se necesita unos estados para saber por donde andamos...y qué hacer a cada momento.
Nota como los valores constantes con más de 1 bit, su nombre cambia a ES_.... aunque luego no los usamos...
Código:
enumeracion AtributosDeCaracteres
    ATRIB_CHAR_DESCONOCIDO = 0
    ATRIB_CHAR_DIGITO = 1
    ATRIB_CHAR_OPERADOR_ASIGNA = 2
    ATRIB_CHAR_OPERADOR_ARIT = 4   ' aritmético... si incluyes buleanos, o comparadores, añade las constantes antes de parentesis (y desplaza esos con sus valores más abajo)
        ES_ATRIB_CHAR_OPERADOR = (ATRIB_CHAR_OPERADOR_ASIGNA or ATRIB_CHAR_OPERADOR_ARIT)
    ATRIB_CHAR_PARENTESIS_ABRE = 8
    ATRIB_CHAR_PARENTESIS_CIERRA = 16
        ES_ATRIB_CHAR_PARENTESIS = (ATRIB_CHAR_PARENTESIS_ABRE or ATRIB_CHAR_PARENTESIS_CIERRA)
    ATRIB_CHAR_ESPACIO = 99  // espacio o tabulador... espacio duro, va hacer difícil que aparezca.
fin enumeracion

Se precisa un array que contendrá los atributos (que nos interesan) de todos los caracteres (que nos interesan).
Código:
array bytes Atributos[0 a 255]

Y rellenar el array de atributos... (el resto de operadores te lo dejo para ti).
Código:
funcion Main
    // empezamos borrando la basura...
    bucle para k desde 0 a 255
        Atributos[k] = ATRIB_CHAR_DESCONOCIDO
    siguiente

    // los dígitos...
    bucle para k desde 48 a 57
        Atributos[k] = ATRIB_CHAR_DIGITO
    siguiente

    // operadores...
    Atributos[43] = ATRIB_CHAR_OPERADOR_ARIT    // '+'
    Atributos[45] = ATRIB_CHAR_OPERADOR_ARIT    // '-'
    Atributos[42] = ATRIB_CHAR_OPERADOR_ARIT    // '*'
       ... el resto de operadores a considerar

    Atributos[61] = ATRIB_CHAR_OPERADOR_ASIGNA  // '='

    // paréntesis...
    Atributos[40] = ATRIB_CHAR_PARENTESIS_ABRE  // '('
    Atributos[41] = ATRIB_CHAR_PARENTESIS_CIERRA  // ')'

    // espacios...
    Atributos[09] = ATRIB_CHAR_ESPACIO  // tab
    Atributos[32] = ATRIB_CHAR_ESPACIO  // spc
fin funcion

Ya tenemos la base, va faltando la función para obtener los tokens con el analizador léxico.
Código:
enumeracion TiposDeToken
    TOKEN_ERROR = 0
    TOKEN_NUMERO =1
    TOKEN_ASIGNA = 2
    TOKEN_OPERADOR =3
    TOKEN_PARENTESIS = 4
    
    TOKEN_IGNORA_ESPACIOS = 9
fin enumeracion

// devuelve el tipo de token hallado y por referencia un string con el valor del token, y el índice (se va actualizando)
// Parámetros:
//     Entrada: es el array de caracteres que se reciben...
//     Indice: es el índice actual siendo analizado. Es un parámetro por referencia.
//     Limite: es el tamaño del array (para no andar preguntando cada vez que se entra a la funcion).
//     Token: el valor a devolver para almacenar... puedes devolver un entero si lo prefieres...
// Devuelve: el tipo de token hallado. Error si el carácter no pertenece a ningún tipo de token que el programa reconoce.
TiposDeToken = funcion GetToken(array chars Entrada[], entero (ref) Indice, entero limite, string (ref) Token)
    AtributosDeCaracteres ch
    entero j, k

    Token = Entrada(indice)
    ch = Atributos[entrada[indice]]
    indice +=1
    Seleccionar caso ch
        caso ATRIB_CHAR_DIGITO            
            Hacer mientras (indice < limite)
                Si (Atributos[entrada[indice]] != ATRIB_CHAR_DIGITO )  // empieza otro token, devolver el número hallado.
                    devolver TOKEN_NUMERO
                fin si
                Token += Entrada(indice)  // concatena otro dígito...
                indice +=1
            repetir
            devolver TOKEN_NUMERO   // fin del array.
        caso ATRIB_CHAR_OPERADOR_ARIT
            devolver TOKEN_OPERADOR
        caso ATRIB_CHAR_OPERADOR_ASIGNA
            //token = "="
            devolver TOKEN_ASIGNA            
        caso ATRIB_CHAR_PARENTESIS_ABRE
            //token = "("
            devolver TOKEN_PARENTESIS
        caso ATRIB_CHAR_PARENTESIS_CIERRA
            //token = ")"
            devolver TOKEN_PARENTESIS
        caso ATRIB_CHAR_ESPACIO  // es idéntico a dígitos, salvando las distancias, y que aquí, no precisa devolver el string del Token
            Token = ""
            Hacer mientras (indice < limite)
                Si (Atributos[entrada[indice]] != ATRIB_CHAR_ESPACIO) // [s]TOKEN_IGNORA_ESPACIOS )[/s]  // fin de espacios...
                    devolver TOKEN_IGNORA_ESPACIOS
                fin si
                indice +=1
            repetir
            devolver TOKEN_IGNORA_ESPACIOS
        resto casos // ATRIB_CHAR_DESCONOCIDO
            Token = ""
            devolver TOKEN_ERROR
    fin seleccion
fin funcion

Y ahora falta la función general que recibe la entrada, genera los tokens partiendo de la entrada recibiday que manda almacenar...
Código:
buleano = funcion CalcularExpresion(char Cadena[100]
    entero j, k
    string Token
    TiposDeToken tTok

    k= tamaño de Cadena
    j=0
    Hacer mientras (j<K)
        tTok = GetToken(cadena, j, k,Token)
        Si (tTok = TOKEN_ERROR)
             mensaje de error
             devolver FALSE
        Sino
            Si (tTok != TOKEN_IGNORA_ESPACIOS)
                GuardarTokenEnPila(Token, tTok) // entrar Token para meter en la pila en la notación elegida (polaca, polaca inversa, etc...)
            fin si
        fin si
    Repetir

    // la función que toma la pila y evalúa la expresión... si la haces sobre la marcha,
    //   si no hay otra precedencia en operadores que el orden de entrada,
    //   esto sobraría... sino, no puede evaluarse hasta procesar toda la entrada.
    Calcular
    
    Devolver True
fin funcion

No he revisado tu código, pero a simple vista, parece subóptimo, de todos modos si dices que te funciona, pués listo...
Añade lo señalado y actualiza como convenga...
Ahora te llega un array de bytes-caracteres y el analizador va hallando los números (múltiples dígitos), operadores y parentesis, además ignora espacios y tabuladores y chequea por caracteres no admitidos...
Nota que es solo un analizador léxico, de expresiones aritméticas numéricas, si metes demasiados dígitos que superen el entero generará error, esa comprobación realmente corresponde al analizador semántico, pero para lo sencillo que es el programa, lo puedes verificar justo antes de llamar a almacenar en la pila... antes de "GuardarTokenEnPila", si es un token numérico.
Nota que te falta rellenar datos... en el array los valores de otros operadores... en Main



P.d.: Fe de erratas (la constante tachada no procede, si no la que se ha puesto a  en su sitio):
Si (Atributos[entrada[indice]] != ATRIB_CHAR_ESPACIO) TOKEN_IGNORA_ESPACIOS )  // fin de espacios...
« Última modificación: 3 Junio 2018, 17:11 pm por NEBIRE » En línea

vhh70

Desconectado Desconectado

Mensajes: 6


Ver Perfil
Re: Ayuda Calculadora
« Respuesta #5 en: 2 Junio 2018, 21:53 pm »

Muchas gracias.
Voy a checar pero como decia antes creo que seria mas sencillo si utilizo apuntadores o estoy equivocado.
Lo que se me complica con los apuntadores es como recorrerlo y luego hacer las operaciones.
En línea

Serapis
Colaborador
***
Desconectado Desconectado

Mensajes: 3.391


Ver Perfil
Re: Ayuda Calculadora
« Respuesta #6 en: 3 Junio 2018, 16:54 pm »

creo que seria mas sencillo si utilizo apuntadores o estoy equivocado.
mmm... no sabes lo que dices.
Tu dices sencillo, por ver 60 líneas de código, con las que no contabas?.
Es el código mínimo, escueto... 2 enumeraciones para saber con que se opera y qué se devuelve (aunque inicialmente son muy parecidas, cuando añades más tokens empieza a distanciarse el parecido) y 2 funciones (4 si se incluye la de meter tokens en la pila, y la última de efectuar el cálculo).

La primera función es la general, la que recibe la entrada chequea el carácter inicial y deriva hacia (la segunda función) el reconocimiento del token según dicho carácter (estado inicial). A su vuelta si no hubo errores y el reconocimiento fue efectivo, se invoca la 3ª función para almacenar el token, y finalmente cuando se termina de reconocer la entrada, toca realizar los cálculos.

Una calculadora la puedes hacer más simple si quieres:
Con la 'pantalla vacía', cuando empiece a escribir dígitos (basta 1 solo), está introduciendo el operando1, luego apenas el usuario introduzca un operador (pulsando la tecla, o escribiendo el carácter si no hay interfaz gráfica), almacenas el lo entrado como primer operando, cuando escriba otro dígito, almacenas el operador, y cuando de nuevo escriba otro operador efectúas la operación con los operandos previos, y el resultado se deja en el operando1... si el segundo operador era el símbolo "=", además muestras el resultado al usuario.
(nota que con la pantalla vacía ambos operandos tienen valor 0, luego si empieza introduciendo un operador, se considera almacenado como operando1 el valor 0).
Si no, cuando de nuevo introduzca un dígito, vuelves a guardar el operador, y tras un nuevo operador, los digitos recién metidos quedan almacenados como el 2º operando, y de nuevo se procesa ambos operandos con el operador introducido, y de nuevo el resultado se queda como el operando 1.

El defecto de este modelo, son 2:
- El primero defecto: el usuario debe introducir las operaciones en orden, ya que la precedencia seguida es 'se ejecuta inmediatamente', luego obliga al usuario a introducir ordenadamente o el resultado final puede ser errado... 5+2*3=, con este diseño de calculadora arrojaría:
opn1 = 5
opr = "+"
si opr = "=" mostrar opn1
opn2 = 2
oprtemp = "*"
opn1 = opn1 opr opn2 = 5 + 2 = 7
opr= oprtemp
si opr = "=" mostrar opn1
opn2 = 3
oprtemp = "="
opn1 = opn1 opr opn2 = 7 * 3 = 21
opr = oprtemp
si opr = "=" mostrar opn1   mostrar 21
Por comodidad al operando1 sería mejor llamarlo acumulador, y al operando2, simplemente operando.

Con precedencia de operadores sería opn1 = 5+(2*3) = 11

- El segundo defecto: Al ser ejecutado de modo inmediato, (carece de memoria, solo mantiene 3 datos). El usuario no puede ver que ha escrito más allá de lo último entrado, es fácil equivocarse y repetir un operando ya escrito con anterioridad, tampoco puede hacer nada más complejo, le exige pensarlo antes de introducir datos, ni puede hacer modificaciones sobre la marcha...

Luego proveer que pueda entrar una expresión completa, es mucho más efectivo, una línea de texto con una expresión donde pueda modificar, añadir, verificar antes de procesar, es un diseño más 'potente' de calculadora...
Al tiempo, si de nuevo te vas conformas con +-*/=, no te compliques más... Esto es, si es un tarea escolar...

...pero desde el momento en que a futuro quieras añadir operandos más complejos (números reales, en diferentes bases numéricas) ú operadores más complejos (como seno, coseno, tangente, random, media aritmética, raíz cuadrada, raíz cúbica, Xor, And, etc... tendrás que permitir operadores en la forma: 'sin', 'cos', 'atn', 'rnd', 'mod' 'sqr', 'sq3', 'xor', 'and'...), sí o sí, vas a necesitar un analizador de tokens... esto será tanto más cierto, cuanto más complejo haya de ser... y cuanto más complejo haya de ser, proveer el mecanismo (el diseño) más eficaz será lo mejor para poder ampliarlo, sin dejarse los sesos en ello... ergo, ahí te he mostrado el camino a seguir... listo para ampliar cuando se precise, falta básicamente proveer un analizador de "identificador" (cuyo código es casi idéntico al de número), junto con algún token alfabetico-alfanumerico, etc...


Lo que se me complica con los apuntadores es como recorrerlo y luego hacer las operaciones.
Para manejar los datos, elige estructuras que sobretodo seas capaz de manejar, porque las conoces y entiendes, aunque no sea del todo óptimo. En primer lugar uno debe lograr que funcione, luego es tiempo de hacer optimizaciones... no tiene sentido que pretendas usar por ejemplo una tabla hash, si no sabes como usarla y menos como coinstruírla o mantenerla.
Primero logra que te funciones y luego ya mirarás de intentar optimizarlo...
Ten en cuenta que la entrada recibida es en un array de bytes-caracteres, realmente al caso es lo más óptimo.

« Última modificación: 3 Junio 2018, 17:00 pm por NEBIRE » En línea

Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
Ayuda con calculadora
Multimedia
fitipal 6 2,885 Último mensaje 10 Junio 2005, 16:35 pm
por fitipal
ayuda con calculadora en vb « 1 2 »
Programación Visual Basic
tisan77 11 3,966 Último mensaje 28 Octubre 2005, 02:05 am
por Leoj90
Ayuda calculadora.
Programación Visual Basic
Goldmoon 7 3,799 Último mensaje 27 Diciembre 2007, 17:36 pm
por Goldmoon
Ayuda con calculadora
Java
painkillerpucela 3 3,076 Último mensaje 19 Diciembre 2008, 21:40 pm
por Sk9ITk5Z
ayuda con una calculadora
Programación Visual Basic
andrer03 3 2,251 Último mensaje 16 Enero 2009, 16:38 pm
por andrer03
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines