Solución al Trabajo Práctico - Septiembre de 2012 EJERCICIO 1 Escriba un programa en C++ que realice las acciones siguientes: 1. Muestre un mensaje en la consola solicitando que se introduzca por consola el valor del semieje mayor (a) y del semieje menor (b) de una elipse. 2. Lea los valores introducidos por el usuario y los almacene en dos variables double llamadas a y b, respectivamente. Debe satisfacerse a b. En caso contrario, mostrar un mensaje indicándolo y terminar. 3. Calcule y muestre en la consola un valor aproximado del perímetro (p) de la elipse obtenido aplicando la fórmula [ p π 3(a + b) ] (3a + b)(a + 3b) Esta expresión para el cálculo aproximado del perímetro de la elipse fue propuesta por el matemático indio Ramanujan en el año 1914. 4. Teniendo en cuenta que el perímetro (p) de la elipse satisface p = 2aπ [ 1 i=1 ] (2i)! 2 (2 i i!) 4 ε 2i 2i 1 donde ε = a2 b 2 a
se denomina excentricidad de la elipse, el programa debe calcular y mostrar en la consola los treinta valores aproximados del perímetro de la elipse obtenidos al desarrollar la serie p 2aπ [ 1 N i=1 ] (2i)! 2 (2 i i!) 4 ε 2i 2i 1 para N igual a 1, 2,..., 30. Cuanto mayor es el valor de N, más cercano está el valor aproximado obtenido al valor exacto del perímetro. En todos los casos, el valor del perímetro de la elipse debe mostrarse en formato científico, con 10 dígitos de precisión. 2 Dpto. de Informática y Automática, UNED
SOLUCIÓN AL TRABAJO PRÁCTICO - SEPTIEMBRE DE 2012 Solución al Ejercicio 1 #include <iostream> #include <iomanip> #include <cmath> const doublepi =3.1415926535; const intn =30; intmain() { doublea,b; std::cout <<"Introduzca el semieje mayor (a): "; std::cin >> a; std::cout <<"Introduzca el semieje menor (b): "; std::cin >> b; if (a <b) { std::cout <<"Error: debe satisfacerse a >= b"; // Cálculo del perímetro mediante la fórmula de Ramanujan std::cout <<"Perimetro (Ramanujan):\t"<< std::scientific << std::setprecision(10) << PI*(3*(a+b) -std::sqrt((3*a+b)*(a+3*b))) << std::endl; // Cálculo del perímetro mediante la serie doubleeps =std::sqrt(a*a-b*b)/a; std::cout <<"Excentricidad: "<< eps << std::endl; double dos_i_factorial=1, i_factorial=1; doublep1 =1; for (inti=1;i<=n;i++) { i_factorial *= i; dos_i_factorial *=2*i*(2*i-1); doublenum =std::pow(dos_i_factorial,2)*std::pow(eps,2*i); doubledenom =std::pow(std::pow(2.0,i)*i_factorial,4 )*(2*i-1); p1 -=num/denom; std::cout <<"Perimetro (N : "<< i <<" ):\t"<< 2*a*PI*p1 <<std::endl; Código 1.1: Programa solución al Ejercicio 1. Dpto. de Informática y Automática, UNED 3
EJERCICIO 2 Escriba un programa en C++ que estime los extremos (máximos y mínimos) locales de la función f(x) = 1 x 2 sin(x) en un intervalo [a, b]. El algoritmo a aplicar consiste en analizar el valor de la función en los puntos x i = a + b a N i para i : 1,...,N 1 comparando f(x i 1 ), f(x i ) y f(x i+1 ), a fin de determinar si la función tiene en x i un mínimo o máximo relativo. Para determinar si cada extremo del intervalo es un máximo o un mínimo local, debe compararse f(a) con f(x 1 ) y f(b) con f(x N 1 ). El programa debe realizar las acciones siguientes: 1. Solicitar al usuario que introduzca los extremos del intervalo: a y b. Si no se satisface b > a, mostrar un mensaje en la consola indicándolo y terminar. 2. Solicitar al usuario que introduzca por consola el valor de N, que debe ser un número entero mayor que dos. Si no se satisface N > 2, mostrar un mensaje en la consola indicándolo y terminar. 3. Evaluar la función f en los puntos x i, con i : 0,..., N, escribiendo en la consola los pares {x i, f(x i ) correspondientes a máximos o mínimos locales, indicando en cada caso si se trata de un máximo o un mínimo. 4 Dpto. de Informática y Automática, UNED
SOLUCIÓN AL TRABAJO PRÁCTICO - SEPTIEMBRE DE 2012 Solución al Ejercicio 2 #include <iostream> #include <cmath> double f(double x) { return1 -x *x *std::sin(x); intmain() { doublea,b; std::cout << "Introduzca los extremos del intervalo [a,b]\n"<< "a: "; std::cin >> a; std::cout <<"b: "; std::cin >> b; if (a >=b ) { std::cout <<"ERROR: Debe satisfacerse a < b"<< std::endl; intn; std::cout <<"Introduzca el numero de puntos (N): "; std::cin >> N; if (! (N >2) ) { std::cout <<"ERROR: N debe ser mayor que dos"<< std::endl; doubleincx = (b-a)/n; // Análisis del extremo a if (f(a) <f(a +incx) ) std::cout <<"Min: "<< a <<",\t"<< f(a) << std::endl; if (f(a) >f(a +incx) ) std::cout <<"Max: "<< a <<",\t"<< f(a) << std::endl; // Análisis de los puntos internos al intervalo for (inti=1;i<n;i++) { if ( f(a+i*incx) < f(a+(i-1)*incx) && f(a+i*incx) < f(a+(i+1)*incx) ) std::cout <<"Min: "<< a+i*incx <<",\t"<< f(a+i*incx) << std::endl; if ( f(a+i*incx) > f(a+(i-1)*incx) && f(a+i*incx) > f(a+(i+1)*incx) ) std::cout <<"Max: "<< a+i*incx <<",\t"<< f(a+i*incx) << std::endl; // Análisis del extremo b if (f(b) <f(b -incx) ) std::cout <<"Min: "<< b <<",\t"<< f(b) << std::endl; if (f(b) >f(b -incx) ) std::cout <<"Max: "<< b <<",\t"<< f(b) << std::endl; Código 1.2: Programa solución al Ejercicio 2. Dpto. de Informática y Automática, UNED 5
EJERCICIO 3 Escriba en C++ un programa que convierta a decimal un número hexadecimal introducido por el usuario a través de la consola. El programa debe realizar las acciones siguientes: 1. Escribir un mensaje en la consola solicitando al usuario que introduzca por consola un número hexadecimal con un máximo de 8 dígitos. 2. Almacenar el número introducido en una variable de tipo std::string llamadanumhex. 3. Comprobar que el número de dígitos del número es menor o igual a ocho. En caso contrario, mostrar un mensaje en la consola y terminar. 4. Comprobar que el número introducido es un número hexadecimal válido. Para ello, comprobar que cada uno de los dígitos del número pertenece al conjunto {0 9, A, B, C, D, E, F. Si no es un número hexadecimal válido, mostrar un mensaje en la consola indicándolo y terminar. 5. Calcular el valor decimal de numhex, suponiendo que numhex representa un número hexadecimal sin signo, y almacenar el valor calculado en una variable del tipo unsigned long int llamadanumdec. 6. Mostrar el valor denumdec en la consola. 6 Dpto. de Informática y Automática, UNED
SOLUCIÓN AL TRABAJO PRÁCTICO - SEPTIEMBRE DE 2012 Solución al Ejercicio 3 #include <iostream> #include <string> intmain() { std::string numhex; std::cout <<"Introduzca el numero hexadecimal: "; std::cin >> numhex; // Comprueba el número de dígitos del número if (numhex.length()>8) { std::cout <<"ERROR: Numero de digitos mayor que 8" << std::endl; // Analiza la cadena de caracteres y convierte a decimal unsigned long intnumdec =0; unsigned long intpeso =1; for (inti =numhex.size()-1;i >=0 ;i--) { if (numhex[i] >= 0 &&numhex[i]<= 9 ) { numdec += (numhex[i]- 0 )*peso; else if (numhex[i] == A ) { numdec +=10*peso; else if (numhex[i] == B ) { numdec +=11*peso; else if (numhex[i] == C ) { numdec +=12*peso; else if (numhex[i] == D ) { numdec +=13*peso; else if (numhex[i] == E ) { numdec +=14*peso; else if (numhex[i] == F ) { numdec +=15*peso; else { std::cout <<"ERROR - Caracter desconocido: "<< numhex[i] << std::endl; peso *=16; std::cout <<"Numero decimal: "<< numdec << std::endl; Código 1.3: Programa solución al Ejercicio 3. Dpto. de Informática y Automática, UNED 7
EJERCICIO 4 En este ejercicio se propone realizar un programa en C++ que calcule la inversa de una matriz 3 3 especificada por el usuario. El programa en C++ debe realizar las acciones siguientes: 1. Mostrar un mensaje en la consola indicando al usuario que introduzca los nueve componentes de la matriz a invertir. El orden en el cual deben introducirse los componentes es el siguiente: en primer lugar los tres primeros números corresponden a la primera fila, a continuación los tres siguientes a la segunda y finalmente los tres últimos a la tercera fila. 2. Calcular el determinante de la matriz A y mostrar su valor en la consola. El determinante de A se representa en lo sucesivo A. 3. Si A 0, calcular la matriz inversa y mostrarla en la consola. Empléese para ello la expresión: A 1 = 1 (Adj (A))T A donde A 1 representa la matriz inversa de A, Adj (A) la matriz adjunta de A y (.) T indica la operación de trasponer la matriz. 4. Si A = 0, mostrar un mensaje en la consola indicándolo y terminar. 5. Como comprobación de que el cálculo de la matriz inversa se ha realizado correctamente, calcular y mostrar en la consola el resultado de multiplicar A por A 1. Si el cálculo es correcto, el resultado debe ser la matriz unidad (unos en la diagonal y cero los demás componentes). Solución al Ejercicio 4 8 Dpto. de Informática y Automática, UNED
SOLUCIÓN AL TRABAJO PRÁCTICO - SEPTIEMBRE DE 2012 #include <iostream> intmain() { // Entrada por consola de los componentes de la matriz std::cout <<"Introduzca los componentes de la matriz:\n"; doublea[3][3]; for (inti=0;i<3;i++) { for (intj=0;j<3;j++) { std::cout <<"A["<<i <<","<<j <<"]: "; std::cin >>A[i][j]; // Cálculo del determinante doubledeta = A[0][0]*A[1][1]*A[2][2] -A[0][0]*A[1][2]*A[2][1] + A[0][1]*A[1][2]*A[2][0] -A[0][1]*A[1][0]*A[2][2] + A[0][2]*A[1][0]*A[2][1] -A[0][2]*A[1][1]*A[2][0]; if (deta ==0) { std::cout <<"El determinante vale cero"<< std::endl; std::cout <<"det(a): "<< deta << std::endl; // Cálculo de la matriz adjunta double adja[3][3]; adja[0][0] = A[1][1]*A[2][2] -A[1][2]*A[2][1]; adja[0][1] = -A[1][0]*A[2][2] +A[1][2]*A[2][0]; adja[0][2] = A[1][0]*A[2][1] -A[1][1]*A[2][0]; adja[1][0] = -A[0][1]*A[2][2] +A[0][2]*A[2][1]; adja[1][1] = A[0][0]*A[2][2] -A[0][2]*A[2][0]; adja[1][2] = -A[0][0]*A[2][1] +A[0][1]*A[2][0]; adja[2][0] = A[0][1]*A[1][2] -A[0][2]*A[1][1]; adja[2][1] = -A[0][0]*A[1][2] +A[0][2]*A[1][0]; adja[2][2] = A[0][0]*A[1][1] -A[0][1]*A[1][0]; // Matriz inversa: cálculo y escritura en consola std::cout <<"inva = "<< std::endl; double inva[3][3]; for (inti=0;i<3;i++) { for (intj=0;j<3;j++) { inva[i][j] =adja[j][i]/deta; std::cout << inva[i][j] <<"\t"; std::cout << std::endl; // Producto A por inva: cálculo y escritura en consola std::cout <<"A * inva = "<<std::endl; doublei[3][3]; for (inti=0;i<3;i++) { for (intj=0;j<3;j++) { I[i][j] =0; for (intk=0;k<3;k++) I[i][j] +=A[i][k] *inva[k][j]; std::cout <<I[i][j] <<"\t"; std::cout << std::endl; Código 1.4: Programa solución al Ejercicio 4. Dpto. de Informática y Automática, UNED 9
EJERCICIO 5 Escriba en C++ un programa que realice las acciones siguientes: 1. Declarar una variable global, llamada dat, que sea un array bidimensional de componentes int, con 8 filas y 8 columnas. Inicializar dicha variable, de manera que los componentes tomen valores cero y uno. 2. Analizar dat con el fin de encontrar cadenas de elementos con valor 1. Dos elementos con valor 1 están en la misma cadena si están en posiciones adyacentes en la horizontal, en la vertical o en alguna diagonal. 3. Muestre en la consola un mensaje indicando, para cada una de las cadenas encontradas, el tamaño de la cadena y la posición (fila, columna) de sus componentes. El tamaño de una cadena es el número de elementos que la componen. Las filas y columnas dedat se numeran considerando que la fila superior es la número 0 y que la columna situada más a la izquierda es la número cero. Por ejemplo, el array bidimensional 0 1 0 0 0 0 0 0 1 0 0 1 1 1 0 0 1 0 1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 contiene las cadenas siguientes: 7 elementos: (0,1) (1,0) (2,0) (3,0) (4,1) (5,1) (5,2) 4 elementos: (1,3) (1,4) (1,5) (2,2) 2 elementos: (3,7) (4,6) 1 elemento: (7,2) 10 Dpto. de Informática y Automática, UNED
SOLUCIÓN AL TRABAJO PRÁCTICO - SEPTIEMBRE DE 2012 Solución al Ejercicio 5 #include <iostream> #include <sstream> intdat[8][8] = { {1,0,0,0,1,1,1,0, {1,1,1,0,0,0,0,0, {1,0,0,0,1,1,0,1, {0,0,0,1,0,0,0,1, {1,0,1,0,1,0,0,1, {1,0,1,0,0,1,0,0, {1,0,0,0,0,0,1,1, {1,1,1,1,1,1,1,1 ; voidimprimematriz() { for (inti=0;i<8;i++) { for (intj=0;j<8;j++) std::cout <<dat[i][j] <<" "; std::cout << std::endl; return; boolprincipiocadena() { // Si encuentra un elemento con valor 1, lo pone a valor 2 y devuelve true // Si ningún elemento tiene valor 1, devuelve false for (inti=0;i<8;i++) for (intj=0;j<8;j++) if (dat[i][j] ==1 ) { dat[i][j] =2; return true; return false; Código 1.5: Programa solución al Ejercicio 5 (1/3). Dpto. de Informática y Automática, UNED 11
boolinspeccionvecinos() { // componente valor 2: pertenece a la cadena, vecinos sin inspeccionar // componente valor 3: pertenece a la cadena, vecinos inspeccionados // Esta función pasa todos los componentes con valor 2 a valor 3, // pasando los vecinos de valor 1 a valor 2 // Si algún componente ha pasado de 1 a 2, devuelve true. // En caso contrario, devuelve false. boolcrececadena = false; for (inti=0;i<8;i++) for (intj=0;j<8;j++) if (dat[i][j] ==2 ) { dat[i][j] =3; if (j>0 &&i>0 &&dat[i-1][j-1] ==1 ) { dat[i-1][j-1] =2; if (j>0 &&dat[i][j-1] ==1 ) { dat[i][j-1] =2; if (i>0 &&dat[i-1][j] ==1 ) { dat[i-1][j] =2; if (i>0 &&j<7 &&dat[i-1][j+1] ==1 ) { dat[i-1][j+1] =2; if (j<7 &&dat[i][j+1] ==1 ) { dat[i][j+1] =2; if (i<7 &&j>0 &&dat[i+1][j-1] ==1 ) { dat[i+1][j-1] =2; if (i<7 &&dat[i+1][j] ==1 ) { dat[i+1][j] =2; if (i<7 &&j<7 &&dat[i+1][j+1] ==1 ) { dat[i+1][j+1] =2; returncrececadena; Código 1.6: Programa solución al Ejercicio 5 (2/3). 12 Dpto. de Informática y Automática, UNED
SOLUCIÓN AL TRABAJO PRÁCTICO - SEPTIEMBRE DE 2012 std::string escribecadena() { // Devuelve un string con todos los componentes de valor 3 de dat intnumelem =0; std::stringstream ss; for (inti=0;i<8;i++) for (intj=0;j<8;j++) if (dat[i][j] ==3) { ss <<"("<<i <<","<<j <<") "; numelem++; std::stringstream ss1; ss1 << numelem <<" elemento"; if (numelem >1)ss1 <<"s"; ss1 <<": "<<ss.str(); returnss1.str(); voidborracadena() { for (inti=0;i<8;i++) for (intj=0;j<8;j++) if (dat[i][j] ==3)dat[i][j] =0; return; intmain() { bool encontradanuevacadena = false; intnumcadenas =0; do { encontradanuevacadena =principiocadena(); //imprimematriz(); if (encontradanuevacadena) { boolcrececadena = false; do { crececadena =inspeccionvecinos(); while (crececadena); std::cout << escribecadena() << std::endl; numcadenas++; borracadena(); while (encontradanuevacadena); if (numcadenas==0) { std::cout <<"No se ha encontrado ninguna cadena"<< std::endl; Código 1.7: Programa solución al Ejercicio 5 (3/3). Dpto. de Informática y Automática, UNED 13