• Publicidad

Aritmética en Perl

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Aritmética en Perl

Notapor DDTenas » 2010-05-17 23:28 @020

"Hola" :D

Necesito ayuda con un proyecto, el cual consiste en lo siguiente:
Se ingresan una operación aritmética como por ejemplo esta (8-3)*(4*2).

Eso lo ingresamos a un arreglo, yo lo coloco en el arreglo de la siguiente forma @Dats=split("",$cadena);
con eso ya tengo carácter en un arreglo. Pero lo que nos piden es:

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
posición del arreglo=---0 1 2 3 4 5 6 7 8 9 10
-------------arreglo=---( 8 - 3 ) * ( 4 * 2 )
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


entonces primero tiene que buscar donde estén los paréntesis para operar lo que se encuentra dentro de ellos.

Adentro de los paréntesis revisa, el primero es número y como lo es lo mete en un arreglo (nos explicaron que pasa a ser posfijo) después se espera un signo y ese signo lo ingresa a una variable (si no es signo tiene que mostrar error) después del signo se espera un número y lo mete al mismo arreglo del anterior, en la siguiente posición del arreglo se ingresa el signo que se guardó en la variable.

Para que se entienda mejor quiere lo siguiente:

Que dé esto
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
Infijo[
-------posición del arreglo=----0 1 2 3 4 5 6 7 8 9 10
--------------------arreglo=----( 8 - 3 ) * ( 4 * 2 )
                                                      ]
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Pase a esto
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
Posfijo[

posición del arreglo=---0 1 2 3 4 5 6
arreglo=----------------8 3 - 4 2 * *
                                                       ]
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


ya teniendo el Posfijo tomaría el primero con utilizando pop y el segundo estos dos datos se ingresarían a una variable y ahora se revisa qué signo es el que está en segunda posición con un if() pienso yo. Ya teniendo este valor se ingresa a otro arreglo vertical (pileta) que seria algo así

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
|4 |  |
|3 |  |
|2 |  |
|1 |  |
|0 | 5|  <---- valor del resultado
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


ahora realizaría lo que sigue y quedaría así

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
|4 |  |
|3 |  |
|2 |  |
|1 | 5|
|0 | 8|  <---- valor del resultado
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


para meterlo sería con un push(), verdad.
El último que entra es el primero que sale.

Entonces estos dos valores se les asigna a dos variables
T1 =8 y T2 = 5

entonces ahora solo verificaría el último signo en el posfijo que es "*" y multiplica las variables T1 * T2 y el resultado lo ingresa otra vez en el arreglo anterior

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
|4 |  |
|3 |  |
|2 |  |
|1 |  |
|0 |40|  <---- valor del resultado
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


y por último se imprimiría 40.

Una restricción es que solo se va a ingresar número de 0 a 9 y las operaciones a realizar pueden ser sin paréntesis.

Si alguien me pudiera ayudar le estaría muy agradecido porque no sé cómo hacer el algoritmo, tal vez me pueden hacer el favor de explicarme cómo hacerlo.

"Si no entienden algo de lo que coloqué, por favor, dígame"

¡Muchas Gracias! :D
DDTenas
Perlero nuevo
Perlero nuevo
 
Mensajes: 2
Registrado: 2010-05-17 19:37 @859

Publicidad

Re: Aritmética en Perl

Notapor explorer » 2010-05-18 04:42 @237

Bienvenido a los foros de Perl en Español, DDTenas.

Primero, decirte que este tema ya salió ayer: Evaluador de expresiones aritméticas .

Segundo, comentarte que la solución propuesta por ti, basada en pilas (piletas), también es muy común (de hecho, es una forma de representar un árbol, como se comenta en el otro hilo).

La solución que muestras de la notación postfija convirtiendo desde la notación infija, es cuestión de ir leyendo la pila (pileta) desde el último operando introducido, y reduciendo cada operación y sus operandos, al resultado, y dejando este resultado en la pila para el resto de operandos que queden más abajo en esa pila (tienes el algoritmo RPN en la página de Wikipedia que te enlacé antes).

Hay un problema con todo esto... los paréntesis. ¿Por qué? Pues porque los paréntesis modifican el orden de ejecución en la expresión matemática: primero hay que ejecutar las expresiones que están más anidadas (profundas), e ir subiendo hacia el resto de expresiones. Entonces, en la pila, se debería reflejar también esto (los paréntesis), como caracteres que delimitan el inicio y fin de subexpresiones: cuando encuentras un paréntesis de apertura, lo agregas a la pila. Sigues resolviendo. Cuando encuentres el paréntesis de cierre, eliminas los paréntesis y dejas solo el resultado de la expresión que hubiera en medio.

Otra forma es la de ir resolviendo la expresión a medida de que se va leyendo. Quiero decir que vas leyendo carácter a carácter, y cuando llegas a un punto que sabes que ha terminado una subexpresión, la resuelves y dejas el resultado en la pila. Si llegas a unos paréntesis, vas agregando expresiones en la pila, para cuando llegues a los paréntesis de cierre.

Prueba a escribir algo de código y nos lo enseñas.

Actualización: otra forma cómoda de hacerlo es usando algún módulo de Perl ya hecho, como por ejemplo Math::Expression::Evaluator.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
    use Math::Expression::Evaluator;
    my $m = Math::Expression::Evaluator->new;

    print $m->parse("(8-3)*(4*2)")->val(), "\n";
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Aritmética en Perl

Notapor DDTenas » 2010-05-25 00:22 @057

:D Gracias por la ayuda

Solo con una consulta:
Tengo aquí mi código para pasar de infijo a posfijo, ya que lo realicé en Java, pero no sé por qué no me funciona. Tal vez me equivoqué en algunas cosas de Java que no se manejan en Perl, será que me pudieran ayudar a ver qué tengo malo. Si me podrían dar una idea para realizar la operación de posfijo para obtener el resultado se los agradecería.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. $cadena="2+3*5";
  2. #@arreglo=split("",$cadena);
  3. my @result = &pasarposfijo($cadena);
  4. print"$result";
  5.  
  6. sub pasarposfijo{
  7.  
  8. my $cadena = shift;
  9.  
  10. @letras= split("",$cadena);
  11.  
  12. @numero;
  13. @signo;
  14.  
  15. $t= @letras;
  16.  
  17. $pos= 0;
  18. $cola = 0;
  19. for($i=0;i<$t;$i++)
  20. {
  21.    
  22.  
  23.   if($letras[i]>=48 && $letras[i]<=57)
  24.     {        
  25.   $numero[pos]=$letras[i];
  26.    
  27.     $pos++;            
  28.  
  29.     }
  30.  
  31.  
  32.    if($letras[i] eq "+" || $letras[i] eq "-" || $letras[i] eq "*" || $letras[i] eq "/")
  33.  {
  34.     if($cola==0){
  35.      $signo[cola]=$letras[i];
  36.          $cola++;
  37.             }
  38.   elsif($cola>0){
  39.            my $ant = &precedencia($signo[$cola-1]);
  40.            my $pre = &precedencia($letras[i]);
  41.        if(($ant ==2 && $pre==1)|| ($ant==1 && $pre==2)  || ($ant==$pre)){
  42.  
  43.         $cola--;
  44.         $m = 0;
  45.         $pm = $signo[cola];
  46.         $signo[cola]=$m;
  47.         $numero[pos]=$pm;
  48.         $pos++;
  49.         $signo[cola]=$letras[i];
  50.         $cola++;
  51.            }
  52. elsif($pre>$ant){
  53.    $signo[cola]=$letras[i];
  54.    $cola++;
  55.  
  56.               }
  57. elsif($ant>$pre){
  58. $m = 0;
  59. while($cola>0){
  60. $cola--;
  61. $pm = $signo[cola];
  62.  
  63. $signo[cola]= $m;
  64. $numero[pos]= $pm;
  65. $pos++;
  66.  
  67. }
  68. $signo[cola]= $letras[i];
  69. $cola++;}
  70.  
  71.        
  72. }
  73. }
  74. }
  75.    while($cola>0){
  76.   $cola--;
  77.   $numero[pos]= $signo[cola];
  78.   $pos++;
  79.  
  80.  
  81.   }
  82.    
  83.   $posfijo= "";
  84.    
  85.   for($i=0;$i<$t;$i++)
  86. {
  87.    $posfijo += $numero[i]+" ";
  88.    
  89. }
  90.  
  91.    return $posfijo;
  92.  
  93. }
  94.  
  95.  
  96.  
  97.  
  98.  
  99.  
  100.  
  101. sub precedencia {
  102.  
  103. my $c = shift;
  104.  
  105. $pre=0;
  106.  
  107. if($c=="+")
  108. { $pre= 0;}
  109.  
  110. if($c=="-")
  111. {$pre=0;
  112. }
  113.  
  114. if($c=="*")
  115. {
  116.  $pre=1;
  117. }
  118. if($c=="/")
  119. {$pre=2;}
  120.  
  121. return($pre);
  122.  
  123.  
  124. }
  125. <>;
  126.  
  127.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
DDTenas
Perlero nuevo
Perlero nuevo
 
Mensajes: 2
Registrado: 2010-05-17 19:37 @859

Re: Aritmética en Perl

Notapor explorer » 2010-05-25 06:51 @327

Estos son los problemas que he encontrado

* líneas 12 y 13. En Perl, no se suelen declarar variables de esa manera. Si no estás usando el modo estricto (ver al final), entonces es mejor no poner nada: las variables serán creadas en el momento de ser usadas

* línea 23. @letras almacena las letras de la $cadena. NO su representación ASCII. Lo correcto sería
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.   if ($letras[$i] ge '0'  and  $letras[$i] le '9')
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

* líneas 23, 25, 32, 35, 40, 49, 53, 68 y 87. Es $i, no i.

* líneas 25, 47, 64 y 77. Es $pos, no pos.

* líneas 32 y 41. Es siempre mejor usar 'or' que '||', y 'and' que '&&', por cuestiones de precedencia de operadores.

* líneas 35, 45, 46, 49, 53, 61, 63, 68 y 77. Es $cola, no cola.

* líneas 107, 110, 114 y 118. Las comparaciones con caracteres hay que realizarlas con los operadores de comparación 'eq', 'ne', 'gt', 'lt', 'ge' y 'le', no con los operadores de comparación numéricos. Debes cambiar todos los '==' por 'eq'.


Recomendaciones:
* usa siempre 'use warnings;' para que Perl te ayude a programar bien en Perl.
* usa siempre 'use strict;' para que Perl te obligue a programar bien en Perl.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España


Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 1 invitado

cron