LENGUAJES DE PROGRAMACIÓN Solución al Trabajo Práctico - Septiembre de 2016 EJERCICIO 1 El método del punto fijo es un método para resolver una ecuación de la forma f (x) = x El método consiste en elegir un valor inicial x0 y realizar la iteración xi+1 = f (xi ) hasta que la diferencia |xi+1 − xi | sea inferior a una determinada tolerancia. Escriba un programa en C++ que aplique el método del punto fijo a la resolución de la ecuación σ · 1.99 − 0.41 · x w + 18.70 · K x 2 w 2 − 38.48 · x 3 w + 53.85 · x 4 w = x donde w = 2.5, σ = 24.89 y K = 52. Escoja como valor inicial para la iteración x0 = 0.25 y un valor de la tolerancia igual a 1E − 3. El programa debe ir escribiendo en la consola los valores xi y |f (xi ) − xi | para i = 0, 1, . . . , en formato fijo y con 6 dígitos decimales. Si el número de iteraciones alcanza un cierto valor maxIter = 50, el programa debe finalizar indicando que el método ha excedido el número máximo de iteraciones. LENGUAJES DE PROGRAMACIÓN Incluya en la memoria del trabajo dos capturas de pantalla de la salida por consola. En una de las capturas de pantalla deben mostrarse los resultados de las primeras iteraciones. En la otra captura de pantalla deben mostrarse los resultados de las últimas iteraciones. A continuación, modifique el valor del número máximo de iteraciones a maxIter = 200 y ejecute nuevamente el programa. Incluya en la memoria una captura de pantalla donde se muestre en este caso el resultado obtenido en las últimas iteraciones. 2 Dpto. de Informática y Automática, UNED SOLUCIÓN AL TRABAJO PRÁCTICO - SEPTIEMBRE DE 2016 Solución al Ejercicio 1 #include <iostream> #include <cmath> #include <iomanip> const double Tolerancia = 1E-3; const double w = 2.5; const double sigma = 24.89; const double K = 52; const double x0 = 0.25; const int maxIter = 200; // 50; double f(double x) { double xw = x/w; const double c[] = {1.99,-0.41,18.70,-38.48,53.85}; double y = c[0]; double powxw = 1; for (unsigned int i=1; i<=4; i++) { powxw *= xw; y += c[i]*powxw; } return std::pow( K/(sigma*y), 2.0 ); } int main() { // Valores iniciales int i = 0; double x = x0; // x_{i} bool iterar = true; // Iteración while ( iterar && i <= maxIter ) { double fx = f(x); // x_{i+1} double err = std::fabs(x-fx); std::cout << "i = " << i << std::fixed << std::setprecision(6) << "\tx = " << x << "\tabs(x-f(x)) = " << err << std::endl; iterar = ( err >= Tolerancia ); x = fx; i++; } if ( iterar ) std::cout << "Alcanzado numero maximo de iteraciones" << std::endl; return 0; } Código 1.1: Programa solución al Ejercicio 1. Dpto. de Informática y Automática, UNED 3 LENGUAJES DE PROGRAMACIÓN EJERCICIO 2 Escriba un programa en C++ que calcule y escriba en la consola el producto de dos números naturales leídos de un fichero de texto. Cada número está escrito en una línea diferente del fichero, por lo que éste contiene dos líneas de texto. El programa debe realizar las acciones siguientes: 1. Solicitar y leer el nombre del fichero. Mediante un mensaje en la consola, solicitar al usuario que introduzca el nombre del fichero de texto donde están escritos los dos números. Leer el nombre introducido por el usuario. 2. Leer el fichero. Abrir para lectura el fichero de texto. Si se produce error, terminar. En caso contrario, leer el contenido del fichero. Dado que los números escritos en el fichero pueden ser lo suficientemente grandes como para estar fuera del rango de los tipos de datos de los números enteros, el programa almacenará cada uno de los dos números en un string. 3. Comprobar que cada uno de los dos strings leídos contiene un número natural. Para ello, debe comprobarse que todos los componentes de los strings son dígitos. En caso contrario, mostrar un mensaje indicándolo y terminar. 4. Comprobar que los números naturales están dentro de los límites para las variables de tipo unsigned long int. Si alguno de los números leídos está fuera del rango de valores de este tipo de dato, mostrar un mensaje indicándolo y terminar. 5. Conversión de tipo. Almacenar los números naturales escritos en los dos strings en sendas variables del tipo unsigned long int. 6. Comprobar que el producto de los dos números está dentro de los límites para las variables de tipo unsigned long int. Si no lo está, mostrar un mensaje indicándolo y terminar. 7. Mostrar en la consola el resultado de la multiplicación de los dos números. 8. Terminar. 4 Dpto. de Informática y Automática, UNED SOLUCIÓN AL TRABAJO PRÁCTICO - SEPTIEMBRE DE 2016 Solución al Ejercicio 2 #include <iostream> #include <string> #include <fstream> #include <limits> #include <sstream> const unsigned long int MAX = std::numeric_limits<unsigned long int>::max(); int main() { // Nombre del fichero std::cout << "Nombre del fichero: "; std::string nombreFich; std::cin >> nombreFich; // Apertura del fichero de comandos para lectura std::ifstream inFich(nombreFich.c_str(), std::ios::in); if (!inFich) { std::cout << "ERROR al abrir fichero " << nombreFich << std::endl; return 1; } // Lectura de dos palabras del fichero std::string palabra1, palabra2; inFich >> palabra1; if (inFich.eof()) { std::cout << "Datos no validos en el fichero" << std::endl; return 0; } inFich >> palabra2; inFich.close(); // Comprobar que lo leido son numeros naturales for (unsigned int i=0; i<palabra1.size(); i++) if (palabra1[i] < '0' || palabra1[i] > '9') { std::cout << "Dato no valido: " << palabra1 << std::endl; return 0; } for (unsigned int i=0; i<palabra2.size(); i++) if (palabra2[i] < '0' || palabra2[i] > '9') { std::cout << "Dato no valido: " << palabra2 << std::endl; return 0; } Código 1.2: Programa solución al Ejercicio 2 (inicio). Dpto. de Informática y Automática, UNED 5 LENGUAJES DE PROGRAMACIÓN } // Comprobación de que los números están dentro de los límites std::stringstream ss; ss << MAX; std::string sMAX = ss.str(); bool palabra1_fueraLimite = sMAX.size() < palabra1.size() || (sMAX.size() == palabra1.size() && sMAX < palabra1); if ( palabra1_fueraLimite ) { std::cout << "Primer entero fuera de limite" << std::endl; return 0; } bool palabra2_fueraLimite = sMAX.size() < palabra2.size() || (sMAX.size() == palabra2.size() && sMAX < palabra2); if ( palabra2_fueraLimite ) { std::cout << "Segundo entero fuera de limite" << std::endl; return 0; } // Almacenar los números en variables del tipo unsigned long int unsigned long int num1 = 0, num2 = 0; unsigned long int expo = 1; for (unsigned int i=0; i<palabra1.size(); i++) { num1 += (palabra1[palabra1.size()-i-1] - '0')*expo; expo *= 10; } expo = 1; for (unsigned int i=0; i<palabra2.size(); i++) { num2 += (palabra2[palabra2.size()-i-1] - '0')*expo; expo *= 10; } // Comprobación de que el producto está dentro de límite if ( num2 > MAX / num1 ) { std::cout << "El producto esta fuera de limites" << std::endl; return 0; } std::cout << "Resultado: " << num1 * num2 << std::endl; return 0; Código 1.3: Programa solución al Ejercicio 2 (final). 6 Dpto. de Informática y Automática, UNED SOLUCIÓN AL TRABAJO PRÁCTICO - SEPTIEMBRE DE 2016 EJERCICIO 3 El objetivo es nuevamente calcular el producto de dos números naturales escritos en un fichero de texto, pero en esta ocasión la estrategia a seguir es diferente ya que se pretende poder calcular el producto de números naturales arbitrariamente largos. El programa debe realizar las acciones siguientes (obsérvese que las tres primeras coinciden con las del ejercicio anterior): 1. Solicitar y leer el nombre del fichero. Mediante un mensaje en la consola, solicitar al usuario que introduzca el nombre del fichero de texto donde están escritos los dos números. Leer el nombre introducido por el usuario. 2. Leer el fichero. Abrir para lectura el fichero de texto. Si se produce error, terminar. En caso contrario, leer el contenido del fichero almacenando cada uno de los dos números en un string. 3. Comprobar que cada uno de los dos strings leídos contiene un número natural. Para ello, debe comprobarse que todos los componentes de los strings son dígitos. En caso contrario, mostrar un mensaje indicándolo y terminar. 4. Conversión de tipo. Almacenar los números naturales escritos en los dos strings en sendos vectores de int, de manera que cada dígito del número quede almacenado en un componente del vector. 5. Multiplicación de los dos números naturales. La multiplicación debe realizarse aplicando el procedimiento clásico empleado al operar con “lápiz y papel”. El algoritmo de la multiplicación debe aplicarse operando los dos vectores de dígitos, obteniéndose como resultado otro vector de dígitos. El procedimiento clásico de multiplicación con lápiz y papel consiste en ir multiplicando por el primer factor los dígitos del segundo factor, comenzando por el menos significativo. Los resultados obtenidos se suman desplazados cada uno una posición hacia la izquierda respecto al anterior. A continuación se muestra un ejemplo. × 1 15 115 132 385474365678 3 927371828393 418974627150 642309703628 988656159172 76 45 80 4 20 6. Mostrar el resultado en la consola y terminar. Dpto. de Informática y Automática, UNED 7 LENGUAJES DE PROGRAMACIÓN Solución al Ejercicio 3 #include <iostream> #include <string> #include <fstream> #include <vector> int main() { // Nombre del fichero std::cout << "Nombre del fichero: "; std::string nombreFich; std::cin >> nombreFich; // Apertura del fichero de comandos para lectura std::ifstream inFich(nombreFich.c_str(), std::ios::in); if (!inFich) { std::cout << "ERROR al abrir fichero " << nombreFich << std::endl; return 1; } // Lectura de dos palabras del fichero std::string palabra1, palabra2; inFich >> palabra1; if (inFich.eof()) { std::cout << "Datos no validos en el fichero" << std::endl; return 0; } inFich >> palabra2; inFich.close(); // Comprobar que lo leido son numeros naturales for (unsigned int i=0; i<palabra1.size(); i++) if (palabra1[i] < '0' || palabra1[i] > '9') { std::cout << "Dato no valido: " << palabra1 << std::endl; return 0; } for (unsigned int i=0; i<palabra2.size(); i++) if (palabra2[i] < '0' || palabra2[i] > '9') { std::cout << "Dato no valido: " << palabra2 << std::endl; return 0; } // Almacenar los números en vectores // índice 0 del vector = digito menos significativo del número std::vector<int> num1, num2; for (int i=palabra1.size()-1; i>=0; i--) num1.push_back(palabra1[i] - '0'); for (int i=palabra2.size()-1; i>=0; i--) num2.push_back(palabra2[i] - '0'); Código 1.4: Programa solución al Ejercicio 3 (inicio). 8 Dpto. de Informática y Automática, UNED SOLUCIÓN AL TRABAJO PRÁCTICO - SEPTIEMBRE DE 2016 } // Producto std::vector<int> resultado; for (unsigned int j=0; j<num2.size(); j++) { std::vector<int> resultadoP; // num2[j] * num1 int acarreoP = 0; for (unsigned int i=0; i<num1.size(); i++) { int prod = num1[i] * num2[j] + acarreoP; resultadoP.push_back( prod % 10 ); acarreoP = prod / 10; } if ( acarreoP != 0 ) resultadoP.push_back( acarreoP); // Desplaza y suma int acarreoS = 0; for (unsigned int i=0; i<resultadoP.size(); i++) { if ( resultado.size() > j + i ) { int suma = resultado[j+i] + resultadoP[i] + acarreoS; resultado[j+i] = suma % 10; acarreoS = suma / 10; } else { int suma = resultadoP[i] + acarreoS; resultado.push_back(suma %10); acarreoS = suma / 10; } } if (acarreoS != 0) resultado.push_back(acarreoS); } // Mostrar resultado en la consola std::cout << "FACTORES:" << std::endl; for (int i=num1.size()-1; i>=0; i--) std::cout << num1[i]; std:: cout << std::endl; for (int i=num2.size()-1; i>=0; i--) std::cout << num2[i]; std:: cout << "\nPRODUCTO:\n"; bool noCero = false; for (int i=resultado.size()-1; i>=0; i--) { if (noCero || resultado[i] != 0) { // Elimina ceros a la izquierda std::cout << resultado[i]; noCero=true; } } if (!noCero) std::cout << "0"; std::cout << std::endl; return 0; Código 1.5: Programa solución al Ejercicio 3 (final). Dpto. de Informática y Automática, UNED 9 LENGUAJES DE PROGRAMACIÓN EJERCICIO 4 El algoritmo de Karatsuba permite realizar la multiplicación de dos números enteros grandes por medio de la multiplicación, suma y resta de números enteros más pequeños. Un caso particular del algoritmo de Karatsuba permite calcular el producto de dos números enteros x e y, expresados de la forma: x = x1 · 103 + x0 y = y1 · 103 + y0 de la manera siguiente: x · y = z2 · 106 + z1 · 103 + z0 donde z2 , z1 y z0 se calculan de la forma siguiente: z2 = x1 · y1 z0 = x0 · y0 z1 = (x1 + x0 ) · (y1 + y0 ) − z2 − z0 En la Figura 1.1 se muestra un ejemplo de aplicación del algoritmo. Obsérvese que las multiplicaciones necesarias para calcular z2 , z1 y z0 , pueden ser calculadas aplicando este mismo algoritmo de forma recursiva si al menos uno de los dos factores es mayor que 999. Si los dos factores son menores que 999, el producto se realiza de la manera ordinaria. Escribir un programa en C++ que realice las acciones siguientes: 1. Solicitar que el usuario introduzca por consola dos números enteros. 2. Comprobar que el producto de los dos números está dentro de los límites para las variables del tipo long long int. Si no lo está, mostrar un mensaje indicándolo y terminar. 3. Calcular el producto de los dos números aplicando el algoritmo de Karatsuba. 4. Mostrar el resultado en la consola. 5. Terminar. 10 Dpto. de Informática y Automática, UNED SOLUCIÓN AL TRABAJO PRÁCTICO - SEPTIEMBRE DE 2016 Figura 1.1: Ejemplo de aplicación del algoritmo de Karatsuba. Dpto. de Informática y Automática, UNED 11 LENGUAJES DE PROGRAMACIÓN Solución al Ejercicio 4 #include <iostream> #include <limits> #include <cmath> const long long int MAX = std::numeric_limits<long long int>::max(); long long int Karatsuba(long long int x, long long int y) { long long int x1 = x/1000; long long int y1 = y/1000; if ( x1 == 0 && y1 == 0 ) return x*y; long long int x0 = x % 1000; long long int y0 = y % 1000; long long int z2 = Karatsuba(x1,y1); long long int z0 = Karatsuba(x0,y0); long long int z1 = Karatsuba(x1+x0,y1+y0) - z2 - z0; return z2*1000000 + z1*1000 + z0; } int main() { // Solicitar que el usuario introduzca los factores std::cout << "Introduzca los factores: "; long long int x, y; std::cin >> x >> y; // Comprobación de que el producto está dentro de los límites if ( std::abs(MAX/x) < y ) { std::cout << "Producto fuera de limite" << std::endl; return 0; } // Aplicación del algoritmo de Karatsuba std::cout << "Producto: " << Karatsuba(x,y) << std::endl; return 0; } Código 1.6: Programa solución al Ejercicio 4. 12 Dpto. de Informática y Automática, UNED