4 (25 %) En este ejercicio se desarrollará el motor de evaluación de una función para una interfaz gráfica de usuario. Dicha interfaz, que se desarrollara en la practica 4 con el empleo del API Swing, permitirá al usuario introducir una función escrita en forma infija y a continuación dibujarla en el intervalo deseado. El motor de evaluación básico se compone de la clase Evaluador, cuya implantación se proporciona parcialmente. Dicha clase permite evaluar una expresión aritmética, formada únicamente por números y operadores binarios: suma, resta, multiplicación, división, y exponenciación (-,+ ,*,/,^). Se pide: Completar el código de la clase Evaluador de forma que el signo menos pueda actuar también como operador unario(con un solo operando). Después de la modificación la clase debe poder evaluar expresiones tales como “-1”, “-(1 – 3)”, “1-(- 1 *8)”, “ 2 * (-2)”, -(-1), etc. No importa que haya espacios entre el operador menos unario y su operando. Utilizar la clase TestEvaluador proporcionada para realizar pruebas. A continuación, créese una clase, Funcion, que tenga como miembro dato una cadena con la expresión de la función y que herede de la clase Evaluador. La cadena especificara un función real en la variable real x formada por cualquier combinación de dicha variable junto con las funciones sin(x),cos(x),tan(x),exp(x) y log(x), por ej.: “3*x + 1 –sin(x)^2 –(2*exp(x)/log(x)) + cos(x)^2 –tan(x) +2/(x^2 + x)”. La clase Funcion deberá tener un método publico llamado eval que devuelva el valor de la función en el punto de evaluación x. Utilícese la clase TestFuncion para realizar pruebas con distintas funciones en distintos puntos de evaluación. Puede verse la ejecución de este fichero sobre la clase Funcion terminada corriendo el archivo “ejecutableEJ4.bat” (utiliza el jar testFuncionEJ4.jar). En la dirección http://www.ideas2work.com/CoreJava7.html se explica como crear ejecutables jar. Por último, y para poner en práctica el dispatching dinámico de métodos, crear una clase abstracta Funcion2 que herede de la clase Evaluador, con las mismas características que la clase Funcion, salvo que ahora el método eval se declara abstracto. A continuación créense tres clases, FuncionTrigonometrica, FuncionExponencial, y FuncionPolinomica, que heredando de la clase Funcion2 implementen el método eval(no serán mas que casos particulares del método eval de la clase Funcion). Por tales funciones se entenderá que sólo contienen combinaciones de [sin(x) cos(x) tan(x)], exp(x), y x respectivamente. En un archivo de aplicación TestPolimorfismoApp.java, declarar: Funcion2 f2[]=new Funcion2[3]; ;f2[0]=new FuncionTrigonometrica(“2*sin(x)*cos(x)”); // seno del ángulo doble ;f2[1]=new FuncionPolinomica(“32*x^5 –160*x^3 +120”);//polinomio de Hermite de orden 5 ;f2[2]=new FuncionExponencial(“(exp(x) – exp(x)^(-1))/2”) //función seno hiperbólico A continuación permitir que sea el usuario quien decida en tiempo de ejecución que función evaluar mediante la llamada a f2[i].eval(x). Se le pedirá por teclado la función que desea evaluar y el punto de evaluación. INDICACIONES Como indicación para el apartado 1, hacer notar que el signo menos unario es equivalente a la multiplicación por –1 de su operando, lo cual a su vez, es equivalente a (0-1)*operando. Con respecto al apartado 2, decir que las funciones sin(x), cos(x), etc., en la cadena de la expresión deberán de ser reemplazadas por su valor numérico correspondiente mediante replaceAll(“cos(x)”,””+Math.cos(x)).A continuación se procederá del mismo modo con las x. Finalmente se hará uso de los métodos heredados de la clase Evaluador para obtener el resultado. Hay que tener en cuenta que cuando un double es menor que 10^3 y mayor que 10^7 la conversión a String se expresa en notación científica, con lo cual el número 0.00001 se convertirá en el String 1E-5, que al sustituir en la expresión no podrá evaluarse como un numero, produciendo un error fatal en el motor de evaluación (clase Evaluador). Es necesario, pues, dar formato al double mediante las siguientes líneas: Double d=(double) 1/1000000; NumberFormat nf = NumberFormat.getInstance(Locale.ENGLISH); nf.setMaximumFractionDigits(20); String correcto =nf.format(d); Produciendo el resultado deseado. Ayuda para la realización del ejercicio 4 A continuación se explica como evaluar una expresión matemática empleando Pilas. Para quien no tenga idea de lo que es una pila puede documentarse con cualquier libro de estructura de datos, o más sencillamente, buscando en google por “estructura de datos pila”. Antes de nada, decir que en el paquete java.util.* se proporcionan bastante implementaciones de estructuras de datos (entre las que se incluye una pila (Stack) además de algoritmos aplicados a ellas. El siguiente código declara y usa una pila de dicho paquete: Stack s=new Stack(); //Apilamos (push) A,B,C en la pila s.push(“A”); s.push(“B”); s.push(“C”); //Sacamos(pop) C,B,A de la pila while(s.size() >0) System.out.println(“”+s.pop); Aunque podría haberse utilizado esta clase, se ha desarrollado una clase propia para implementar una pila. Decir también, que en la clase Pila que se proporciona, push es apilar y pop desapilar. EXPRESION INFIJA, POSTFIJA Y SU ALGORITMO DE EVALUACION La forma habitual de escribir expresiones matemáticas es la infija, que básicamente consiste en un operador binario junto con argumentos a su izquierda y derecha. La evaluación de una expresión en forma inflija puede llegar a ser un tanto tediosa, por esa razón suelen utilizarse otro tipo de notaciones, como son la sufija y postfija. En estas formas la evaluación de una expresión aritmética resulta bastante sencilla de implementar utilizando pilas. A continuación se expone el algoritmo de conversión entre ambas representaciones. El alumno que desee conocer más acerca la notación postfija puede consultar cualquier libro de estructura de datos( en la parte de pilas). Conversión de Notación Inflija a Postfija: Todo lo que se desapila pasa a la salida. Operandos : Pasan inmediatamente a la salida. Paréntesis derecho: Desapilamos todos los símbolos hasta que encontremos un paréntesis izquierdo. Operador: Desapilamos todos los símbolos hasta que encontremos uno de menor precedencia o de igual precedencia con asociatividad por la derecha. A continuación, apilaremos el operador encontrado. Fin de entrada: Desapilamos lo que quede en pila. En la tabla siguiente se resumen la precedencia(de menor a mayor) y asociatividad de cada operador: Operador ^ / * + - Precedencia 3 2 2 1 1 Asociatividad Derecha Izquierda Izquierda Izquierda Izquierda Con un ejemplo quedará claro: Sea la expresión infija: 1 – 2 ^ 3 ^ 3 – (4 + 5 *6) *7 Leemos 1 2 ^ 3 ^ 3 ( 4 + 5 * 6 ) * 7 Fin de entrada Salida 1 1 12 12 123 123 1233 1233 1233 1233 1233 1233 1233 1233 1233 1233 1233 1233 ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ - 4 - 4 -45 -45 -456 -456 -456 -456 -456 *+ *+ *+7 *+7*- Evolución de la Pila Vacía -^ -^ -^^ -^^ - ( - ( - (+ -(+ -(+* -(+* -* -* La expresión en postfija, será, pues: 1 2 3 3 ^ ^ - 4 5 6 * + 7 * - Evaluación de una expresión en postfija utilizando una pila Dada una expresión en postfija, para evaluarla se seguirán dos sencillos pasos: 1-Leemos un carácter de la expresión en infijo. 2-Si es un operando lo metemos en la pila. (Hacemos push(operando)) Si es un operador, desapilamos los dos últimos elementos de la pila y los operamos. El primer elemento desapilado se convertirá en el parámetro derecho del operador, y el segundo en el izquierdo. (Hacemos A=pop(), B=pop() , push( B operado A). Ejemplo: 1 2 – 4 5 ^ 3 * 6 *7 2 2 ^ ^ / - Leemos 1 2 - Evolución de la pila 1 1 2 -1 4 5 ^ 3 * 6 * 7 2 2 ^ ^ / El resultado de la evaluación es –8. -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -8 4 4 5 1024 1024 3 3072 3072 6 18432 18432 7 18432 7 2 18432 7 2 2 18432 7 4 18432 2401 7