Solución al Trabajo Práctico - Septiembre de 2015 EJERCICIO 1 De acuerdo a la Ley del decaimiento radioactivo, la masa de una sustancia radioactiva disminuye a una velocidad que es proporcional a la masa presente de dicha sustancia. Esta ley puede expresarse de la forma siguiente: dy dt = r y para t > 0 (1.1) donde y(t) representa la masa de la sustancia presente en el instante t y r es una constante positiva de proporcionalidad. Si la condición inicial es: con α positivo, entonces la solución es: y(0) = α (1.2) y(t) = α e r t (1.3) Por otra parte, puede obtenerse una solución aproximada a la Ec. (1.1) aplicando el método de integración explícito de Euler: y i+1 y i h = r y i y i+1 = y i h r y i para i = 0,1,... (1.4) donde y i es el valor aproximado de y(t i ). Los valores t 0,t 1,... están equiespaciados: t i = i h. La constante h = t i+1 t i es el tamaño del paso en el tiempo del método numérico. Escriba un programa en C++ que realice las acciones siguientes: 1. Declarar una constante entera llamadam, cuyo valor sea 100.
2. Solicitar al usuario que éste introduzca por consola los valores de r, α y h. Si los valores introducidos no son mayores que cero, terminar. 3. Mostrar en la consola: t i, y(t i ),y i, y(t i ) y i parai = 0,1,...,M. Los valores deben mostrarse en formato científico, con 6 dígitos detrás del punto decimal. El cálculo de y(t i ) deberá realizarse evaluando la Ec. (1.3), invocando un función que debe programar a tal fin y cuya cabecera deberá ser: 4. Terminar double decrad(double t, double alpha, double r); 2 Dpto. de Informática y Automática, UNED
SOLUCIÓN AL TRABAJO PRÁCTICO - SEPTIEMBRE DE 2015 Solución al Ejercicio 1 #include <iostream> #include <iomanip> #include <cmath> // Número de instantes const int M = 100; double decrad(double t, double alpha, double r); int main() { // Entrada por consola std::cout << "Introduzca r, alpha, h: "; double r, alpha, h; std::cin >> r >> alpha >> h; // Comprobación de las entradas if ( r <=0 alpha <= 0 h <= 0 ) { std::cout << "Entrada no valida"<< std::endl; // Cálculo y salida por consola double t_i = 0; double y_i = alpha; std::cout << "t_i \t y(t_i) \t y_i \t y(t_i)-y_i" << std::endl; for (int i=0; i<=m; i++) { double decrad_ti = decrad(t_i, alpha, r); std::cout << std::scientific << std::setprecision(6) << t_i << "\t" << decrad_ti << "\t" << y_i << "\t" << decrad_ti - y_i << std::endl; y_i = y_i - h * r * y_i; t_i = t_i + h; double decrad(double t, double alpha, double r) { return alpha*exp(-r*t); Código 1.1: Programa solución al Ejercicio 1. Dpto. de Informática y Automática, UNED 3
EJERCICIO 2 A continuación se muestra un algoritmo 1 para resolver el sistema lineal de N ecuaciones con N incógnitas donde A es una matriz tridiagonal, Ay = z (1.5) a 1 c 1 0...... 0. b 2 a 2 c 2.... A = 0 b 3 a 3 c 3................ 0.... bn 1 a N 1 c N 1 0...... 0 b N a N (1.6) e y yzson vectores columna den componentes: y = y 1 y 2. z = z 1 z 2. (1.7) y N z N Algoritmo 1: Resolución deay = z cuandoaes la matriz tridiagonal (1.6). Set: w = a 1, y 1 = z 1 w For i = 2,3,...,N End For End v i = c i 1 w w = a i b i v i y i = z i b i y i 1 w j = N 1,N 2,...,1 y j = y j v j+1 y j+1 49 50. 1 Mark H. Holmes, Introduction to Numerical Methods in Differential Equations, Springer, 2007, pp. 4 Dpto. de Informática y Automática, UNED
SOLUCIÓN AL TRABAJO PRÁCTICO - SEPTIEMBRE DE 2015 Escriba un programa en C++ que realice las acciones siguientes: 1. Declarar una constante global entera llamadan y asignarle el valor 4. 2. Comprobar que N es mayor que dos. Si no lo es, mostrar un mensaje indicándolo y terminar. 3. Declarar un array bidimensional, con N filas y N columnas, llamado A. Declarar dos arrays unidimensionales den componentes, llamadosy y z. 4. Solicitar al usuario que introduzca por consola los componentes de A y de z. 5. Comprobar siaes tridiagonal. Si no lo es, mostrar un mensaje en la consola indicándolo y terminar. La comprobación debe realizarse invocando una función que debe programar a tal fin y cuya cabecera debe ser: bool tridiagonal (double A[][N]); La función devuelve true si la matriz argumento es tridiagonal. Una matriz es tridiagonal si todos aquellos elementos que no están situados en la diagonal principal, o en las diagonales adyacentes por encima y por debajo a ésta, son cero. 6. Ejecutar el Algoritmo 1, a fin de calcular el valor de los componentes de y. Debe vigilarse que la variable w no se haga cero, ya que eso produciría error de división por cero. Si w vale cero, mostrar un mensaje en la consola indicando que A no es invertible y terminar. 7. Mostrar en la consola los componentes del vector y calculado. 8. Si el cálculo se ha realizado correctamente, el resultado de Ay z debe ser un vector de N componentes cuyos componentes tengan un valor muy próximo a cero. Calcular dicho vector y mostrar en la consola sus componentes. 9. Terminar. Dpto. de Informática y Automática, UNED 5
Solución al Ejercicio 2 #include<iostream> // Número de incógnitas const int N = 4; bool tridiagonal (double A[][N]); int main() { // N debe ser mayor que 2 if ( N < 3 ) { std::cout << "Error: N vale "<< N << " y debe ser mayor que 2"<< std::endl; // Entrada por consola double A[N][N]; std::cout << "Componentes de A: "; for (int i=0; i<n; i++) { for (int j=0; j<n; j++) { std::cout << "\na("<< i << ","<< j << "):\t"; std::cin >> A[i][j]; double z[n]; std::cout << "Componentes de z: "; for (int i=0; i<n; i++) { std::cout << "\nz("<< i << "):\t"; std::cin >> z[i]; // Comprobar si A es tridiagonal if (!tridiagonal(a)) { std::cout << "A no es tridiagonal"<< std::endl; Código 1.2: Programa solución al Ejercicio 2 (inicio). 6 Dpto. de Informática y Automática, UNED
SOLUCIÓN AL TRABAJO PRÁCTICO - SEPTIEMBRE DE 2015 // Algoritmo // Símbolo algoritmo --- Variable programa // a_i --- A[i-1][i-1] // b_i --- A[i-1][i-2] // c_i --- A[i-1][i] // y_i --- y[i-1] // v_i --- v[i-1] // z_i --- z[i-1] double w = A[0][0]; if ( w == 0 ) { std::cout << "A no es invertible"<< std::endl; double y[n]; y[0] = z[0]/w; double v[n]; for (int i=2; i<=n; i++) { v[i-1] = A[i-2][i-1]/w; w = A[i-1][i-1] - A[i-1][i-2]*v[i-1]; if ( w == 0 ) { std::cout << "A no es invertible"<< std::endl; y[i-1] = ( z[i-1] - A[i-1][i-2]*y[i-2] ) / w; for (int j=n-1; j>=1; j--) { y[j-1] = y[j-1] - v[j]*y[j]; // Salida por consola del vector solución y for (int i=0; i<n; i++) { std::cout << "y("<< i << ") = "<< y[i] << std::endl; // Cálculo vector residuo y salida consola std::cout << "res(0) = " << A[0][0]*y[0] + A[0][1]*y[1] - z[0] << std::endl; for (int i=1; i<n-1; i++) std::cout << "res("<< i << ") = " << A[i][i-1]*y[i-1] + A[i][i]*y[i] + A[i][i+1]*y[i+1] - z[i] << std::endl; std::cout << "res("<< N-1 << ") = " << A[N-1][N-2]*y[N-2] + A[N-1][N-1]*y[N-1] - z[n-1] << std::endl; bool tridiagonal (double A[][N]) { // Elementos por encima de la tridiagonal for (int i=0; i<n; i++) for (int j=i+2; j<n; j++) if ( A[i][j]!= 0 ) return false; // Elementos por debajo de la tridiagonal for (int j=0; j<n; j++) for (int i=j+2; i<n; i++) if ( A[i][j]!= 0 ) return false; return true; Código 1.3: Programa solución al Ejercicio 2 (final). Dpto. de Informática y Automática, UNED 7
EJERCICIO 3 Se desea traducir mensajes a secuencias de bits. Los mensajes están construidos empleando únicamente ocho símbolos: A, B, C, D, E, F, G y H. Para ello, se emplea la tabla de codificación siguiente 2 : A 0 C 1010 E 1100 G 1110 B 100 D 1011 F 1101 H 1111 Mediante este código, el mensaje BACADAEAFABBAAAGAH se representaría mediante la siguiente secuencia de bits: 100010100101101100011010100100000111001111 Escriba un programa en C++ que: 1. Solicite al usuario que éste introduzca por consola una cadena de caracteres. 2. Realice una de las dos acciones siguientes: Si se trata de un mensaje, el programa debe traducirlo a su correspondiente codificación binaria y mostrar ésta por consola. Para ello, el programa debe invocar una función que acepte como argumento un símbolo y devuelva su código equivalente. Si el símbolo pasado como argumento no es ninguno de los ocho posibles símbolos, la función debe lanzar una excepción. Programe dicha función, teniendo en cuenta que su cabecera debe ser: std::string codifica(char c) throw (std::invalid_argument); Si la cadena de caracteres introducida por el usuario no es un mensaje válido, el programa debe mostrar un mensaje indicándolo. En dicho mensaje debe indicarse al usuario en qué posición de la cadena de caracteres se encuentra el primer carácter no válido y cuál es. 3. Termine. 2 https://mitpress.mit.edu/sicp/full-text/sicp/book/node41.html 8 Dpto. de Informática y Automática, UNED
SOLUCIÓN AL TRABAJO PRÁCTICO - SEPTIEMBRE DE 2015 Solución al Ejercicio 3 #include <iostream> #include <string> #include <stdexcept> #include <sstream> std::string codifica(char c) throw (std::invalid_argument); int main() { // Entrada por consola std::cout << "Introduzca una cadena de caracteres:" << std::endl; std::string cadenai; std::cin >> cadenai; // Comprueba si la cadena está vacía if ( cadenai.length() == 0 ) { std::cout << "Error: cadena vacia"<< std::endl; // Codifica el mensaje std::stringstream ss; for (int i=0; i<cadenai.length(); i++) { try { ss << codifica(cadenai[i]); catch ( std::invalid_argument exc ) { std::cout << exc.what() << " en posicion "<< i+1 << ": " << cadenai[i] << std::endl; std::cout << ss.str() << std::endl; Código 1.4: Programa solución al Ejercicio 3 (inicio). Dpto. de Informática y Automática, UNED 9
std::string codifica(char c) throw (std::invalid_argument) { switch (c) { case A : return "0"; case B : return "100"; case C : return "1010"; case D : return "1011"; case E : return "1100"; case F : return "1101"; case G : return "1110"; case H : return "1111"; default: throw std::invalid_argument ("Caracter no valido"); Código 1.5: Programa solución al Ejercicio 3 (final). 10 Dpto. de Informática y Automática, UNED
SOLUCIÓN AL TRABAJO PRÁCTICO - SEPTIEMBRE DE 2015 EJERCICIO 4 En este ejercicio se plantea el problema inverso al del ejercicio anterior: dada una secuencia de bits, encontrar el código equivalente de acuerdo a la tabla de codificación dada en el Ejercicio 3. Escriba un programa en C++ que realice las acciones siguientes: 1. Solicitar al usuario que éste introduzca por consola una cadena de caracteres. 2. Realizar una de las dos acciones siguientes: Si la cadena de caracteres es una secuencia de bits que codifica un mensaje, el programa debe decodificarla y mostrar en la consola el mensaje. Para que la secuencia de bits codifique un mensaje debe poder ser descompuesta en la concatenación de subsecuencias 0, 100, 1010, 1011, 1100, 1101, 1110 y 1111. Si la cadena de caracteres introducida por el usuario no es una secuencia de bits que codifique un mensaje, el programa debe mostrar un mensaje indicándolo. 3. Terminar. Dpto. de Informática y Automática, UNED 11
Solución al Ejercicio 4 #include<iostream> #include<string> #include<stdexcept> #include<sstream> int i = 0; // Índice que recorre la cadena std::string cadenai; // Mensaje codificado void incrementa_i() throw (std::invalid_argument) { i++; if ( i >= cadenai.length() ) throw std::invalid_argument ("Final inesperado de la cadena"); return; int main() { // Entrada por consola std::cout << "Introduzca secuencia de bits:"<< std::endl; std::cin >> cadenai; // Comprueba que la cadena no está vacía if ( cadenai.length() == 0 ) { std::cout << "Error: cadena vacia"<< std::endl; // Comprueba que la cadena sólo contiene bits for ( int j=0; j<cadenai.length(); j++) if (cadenai[j]!= 0 && cadenai[j]!= 1 ) { std::cout << "Error - caracter no valido en posicion " << j+1 << ": "<< cadenai[j] << std::endl; Código 1.6: Programa solución al Ejercicio 4 (inicio). 12 Dpto. de Informática y Automática, UNED
SOLUCIÓN AL TRABAJO PRÁCTICO - SEPTIEMBRE DE 2015 // Decodifica el mensaje std::stringstream ss; try { do { if ( cadenai[i] == 0 ) { // - {A ss << "A"; else { // - {B,C,D,E,F,G,H incrementa_i(); if ( cadenai[i] == 0 ) { // -- {B,C,D incrementa_i(); if ( cadenai[i] == 0 ) { // --- {B ss << "B"; else { // --- {C,D incrementa_i(); if ( cadenai[i] == 0 ) { // ---- {C ss << "C"; else { // ---- {D ss << "D"; else { // -- {E,F,G,H incrementa_i(); if ( cadenai[i] == 0 ) { // --- {E,F incrementa_i(); if ( cadenai[i] == 0 ) { // ---- {E ss << "E"; else { // ---- {F ss << "F"; else { // --- {G,H incrementa_i(); if ( cadenai[i] == 0 ) { ss << "G"; else { ss << "H"; i++; while ( i < cadenai.length() ); catch ( std::invalid_argument exc ) { std::cout << exc.what() << std::endl; std::cout << ss.str() << std::endl; // ---- {G // ---- {H Código 1.7: Programa solución al Ejercicio 4 (final). Dpto. de Informática y Automática, UNED 13