LENGUAJES DE PROGRAMACIÓN Solución al Trabajo

Anuncio
LENGUAJES DE PROGRAMACIÓN
Solución al Trabajo Práctico - Junio de 2015
EJERCICIO 1
Uno de los primeros generadores combinados de números pseudoaleatorios fue
el propuesto por Wichmann y Hill en 1982. El generador de Wichmann-Hill emplea
los siguientes tres generadores lineales congruenciales para obtener tres números
enteros {xi , yi , zi }:
xi = (171 · xi−1 )
mód 30269
yi = (172 · yi−1 )
mód 30307
zi = (170 · zi−1 )
mód 30323
de los cuales se obtiene un número pseudoaleatorio ui en el intervalo (0, 1):
x
yi
zi i
ui =
+
+
30269 30307 30323
mód 1
donde i = 1, 2, . . .
La semilla de este generador son tres números enteros, {x0 , y0 , z0 }, que deben
estar comprendidos entre 1 y 30000.
Escriba un programa en C++ que realice las acciones siguientes:
1. Solicitar al usuario que introduzca por consola la semilla del generador.
2. Comprobar que estos tres números están comprendidos entre 1 y 30000.
Si no lo están, el programa vuelve a solicitar por consola los números al
usuario.
LENGUAJES DE PROGRAMACIÓN
3. Empleando el algoritmo de Wichmann-Hill, obtener 100 números pseudoaleatorios e ir almacenándolos en un array de 100 componentes.
4. Mostrar en la consola el contenido del array. Los números deberán mostrarse en formato fijo, con 5 dígitos detrás del punto decimal.
5. Almacenar los números, en el formato anteriormente indicado y formando
una única columna (es decir, un número por fila), en un fichero de texto
llamado random.txt.
6. Terminar.
2
Dpto. de Informática y Automática, UNED
SOLUCIÓN AL TRABAJO PRÁCTICO - JUNIO DE 2015
Solución al Ejercicio 1
// Fichero: random.cpp
#include <iostream>
#include <cmath>
#include <iomanip>
#include <fstream>
#include <string>
const unsigned int N
const int c1=171, m1
const int c2=172, m2
const int c3=170, m3
= 100;
= 30269;
= 30307;
= 30323;
const std::string nombreFich = "random.txt";
int main() {
int Xt, Yt, Zt;
// Entrada semilla por consola (enteros entre 1 y 30000)
do {
std::cout << "Introduzca 3 valores enteros:"<< std::endl;
std::cin >> Xt >> Yt >> Zt;
} while (Xt<1 ||Xt>30000 ||Yt<1 ||Yt>30000 ||Zt<1 ||Zt>30000);
}
// Generador de Wichman-Hill
double U_RH[N];
for (unsigned int i=0; i<N; i++) {
Xt = (c1*Xt) % m1;
Yt = (c2*Yt) % m2;
Zt = (c3*Zt) % m3;
U_RH[i] = fmod( ((double)Xt)/m1 + ((double)Yt)/m2 + ((double)Zt)/m3, 1);
}
// Muestra resultado en consola
for (unsigned int i=0; i<N; i++) {
std::cout << "u["<< i << "]: "<<
std::fixed << std::setprecision(5) << U_RH[i] << std::endl;
}
// Apertura fichero para escritura
std::ofstream outFich(nombreFich.c_str(),
std::ios::out |std::ios::trunc);
if (!outFich) {
std::cout << "ERROR al abrir fichero"<< std::endl;
return 1;
}
// Graba resultado en fichero
for (unsigned int i=0; i<N; i++) {
outFich << std::fixed << std::setprecision(5) <<
U_RH[i] << std::endl;
}
outFich.close();
return 0;
Código 1.1: 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, a partir de una secuencia de 2 · N números
pseudoaleatorios, obtenga N = 45 posiciones aleatorias uniformemente distribuidas sobre una superficie plana rectangular de longitud L = 30 mm y altura
A = 2 mm. Para ello, el programa debe realizar las acciones siguientes:
1. El número de posiciones N, así como la longitud (L) y altura (A) de la
superficie, son constantes del programa: N = 45, L = 30, A = 2.
2. Abrir para lectura un fichero de texto llamado random.txt, en el cual hay
escrita una columna de números pseudoaleatorios. Estos números pueden
ser los obtenidos de ejecutar el programa del ejercicio anterior o cualquier
otra secuencia de números pseudoaleatorios.
3. Almacenar el contenido completo del fichero en un vector de double llamado randomNums.
4. Si el vector contiene menos de 2 · N componentes, mostrar un mensaje de
error y terminar.
5. Operar de la forma siguiente los primeros 2·N números del vector. Por cada
pareja de números, {u2i , u2i+1 }, calcular una posición aleatoria {xi , yi } de la
forma siguiente:
xi = L · u2i
yi = A · u2i+1
donde i = 0, . . . , N − 1.
6. Almacenar las posiciones en un fichero de texto llamado posiciones.txt. Deberán almacenarse en dos columnas: en la primera las posiciones xi y en la
segunda las correspondientes posiciones yi . Deberán expresarse en formato
fijo, con 3 dígitos detrás del punto decimal.
7. Terminar.
4
Dpto. de Informática y Automática, UNED
SOLUCIÓN AL TRABAJO PRÁCTICO - JUNIO DE 2015
Solución al Ejercicio 2
// Fichero: posicAleat.cpp
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <vector>
const unsigned int N = 45;
const double L = 30;
const double A = 2;
const std::string nombreFichI = "random.txt";
const std::string nombreFichO = "posiciones.txt";
int main() {
// Apertura del fichero para lectura
std::ifstream inFich(nombreFichI.c_str(), std::ios::in);
if (!inFich) {
std::cout << "ERROR al abrir fichero"<< std::endl;
return 1;
}
// Lectura de datos del fichero e inclusión en vector
std::vector<double> randomNums;
while (!inFich.eof()) {
double rn;
inFich >> rn;
randomNums.push_back(rn);
}
inFich.close();
// Comprobar que el vector contiene al menos 2*N elementos
if ( randomNums.size() < 2*N) {
std::cout << "Error: el fichero contiene "
<< randomNums.size()
<< "elementos y deberia contener al menos "
<< 2*N << std::endl;
return 1;
}
// Apertura del fichero para escritura
std::ofstream outFich(nombreFichO.c_str(),
std::ios::out |std::ios::trunc);
if (!outFich) {
std::cout << "ERROR al abrir fichero"<< std::endl;
return 1;
}
for (unsigned int i=0; i<2*N; i+=2) {
outFich << std::fixed << std::setprecision(3) <<
L*randomNums[i] << "\t"<< A*randomNums[i+1] << std::endl;
}
outFich.close();
return 0;
}
Código 1.2: Solución al Ejercicio 2.
Dpto. de Informática y Automática, UNED
5
LENGUAJES DE PROGRAMACIÓN
EJERCICIO 3
Considérense N = 45 círculos de radio r = 0.5 mm distribuidos aleatoriamente
sobre una superficie rectangular de L = 30 mm de longitud y A = 2 mm de altura.
Los círculos que se encuentran sobre la superficie se agrupan en conjuntos de la
manera siguiente:
– Cada círculo debe pertenecer a un único conjunto.
– Dos círculos entre los cuales existe solapamiento deben estar en el mismo
conjunto. Se considera que existe solapamiento entre dos círculos si la distancia entre sus centros es menor o igual que 2 · r.
Escriba un programa en C++ que cumpla las especificaciones siguientes:
– El número de círculos (N) y su diámetro (2 · r) deben ser constantes del
programa.
– El programa debe leer las posiciones de los centros de los N círculos de
un fichero de texto llamado posiciones.txt, que contiene dos columnas de
números reales expresados en formato fijo, con 3 dígitos detrás del punto
decimal. Los números de la primera columna son la coordenada x del centro
del círculo y los de la segunda columna la correspondiente coordenada y.
Este fichero podría ser, por ejemplo, el obtenido al ejecutar el programa
escrito en el ejercicio anterior.
– Si el fichero posiciones.txt contiene menos de 2 · N números, el programa
debe mostrar un mensaje de error y terminar.
– El programa debe agrupar los círculos en conjuntos.
– Cada conjunto está compuesto por uno o más círculos. El programa debe
escribir en un fichero de texto llamado nElemConj.txt el número de círculos de que consta cada conjunto. Los números se escribirán formando una
columna. El orden de escritura de los números es irrelevante.
Puede usar en el programa las estructuras de datos que estime convenientes.
La figura mostrada a continuación es un ejemplo que pretende ilustrar la clasificación de los círculos en conjuntos. Por simplicidad en este ejemplo se consideran
6
Dpto. de Informática y Automática, UNED
SOLUCIÓN AL TRABAJO PRÁCTICO - JUNIO DE 2015
C7
C6
C3
C1
C13
C2
C11
C12
C4
C9
C10
C15
C8
C14
C5
Figura 1.1: Los círculos mostrados en esta figura se clasifican en 5 conjuntos: {C7 },
{C2 , C11 , C9 , C15 }, {C6 , C1 , C13 , C4 , C10 }, {C3 , C12 }, {C8 , C14 , C5 }
sólo N = 15 círculos. Los círculos se han etiquetado C1 , . . . , C15 con el propósito
de facilitar referirse a ellos al indicar los círculos pertenecientes a cada conjunto.
Dados los conjuntos del ejemplo mostrado en la Figura 1.1, la salida del programa
debería ser los números siguientes escritos en cualquier orden en una columna:
1, 4, 5, 2, 3.
Dpto. de Informática y Automática, UNED
7
LENGUAJES DE PROGRAMACIÓN
Solución al Ejercicio 3
// Fichero: circulos.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cmath>
const unsigned int N = 45;
const double r2 = 2*0.5;
const std::string nombreFichI = "posiciones.txt";
const std::string nombreFichO = "nElemConj.txt";
struct Circulo {
double xpos;
double ypos;
int
iConjunto; // Campo que indica el conjunto del circulo
};
int main() {
// Apertura del fichero de posiciones para lectura
std::ifstream inFich(nombreFichI.c_str(), std::ios::in);
if (!inFich) {
std::cout << "ERROR al abrir fichero "
<< nombreFichI << std::endl;
return 1;
}
// Carga de N circulos en el vector
std::vector<Circulo> circulos;
while (!inFich.eof() && circulos.size()<N ) {
// Coordenadas del centro
Circulo c;
inFich >> c.xpos >> c.ypos;
c.iConjunto = 0;
circulos.push_back(c);
}
inFich.close();
// Comprueba que se hayan leido 2*N valores del fichero
if ( circulos.size() < N ) {
std::cout << "ERROR: el fichero "<< nombreFichI <<
" contiene menos de "<< 2*N << " valores"<< std::endl;
return 1;
}
Código 1.3: Solución al Ejercicio 3 (parte inicial).
8
Dpto. de Informática y Automática, UNED
SOLUCIÓN AL TRABAJO PRÁCTICO - JUNIO DE 2015
}
// Asigna valor al campo iConjunto
int nConjunto = 1;
for (int i=0; i<circulos.size(); i++) {
if (circulos[i].iConjunto == 0) {
circulos[i].iConjunto = nConjunto;
nConjunto++;
}
for (int j=i+1; j<circulos.size(); j++) {
// Distancia entre los centros de los círculos i y j
double d = pow( pow(circulos[i].xpos-circulos[j].xpos,2) +
pow(circulos[i].ypos-circulos[j].ypos,2), 0.5);
if ( d <= r2 ) {
// Los círculos i y j solapan
if ( circulos[j].iConjunto != 0 ) { // Si j pertenece a un grupo
int iConjuntoAlias = circulos[j].iConjunto;
// Todos los circulos del grupo de j pasan a ser del grupo de i
for (int k=0; k<circulos.size(); k++)
if ( circulos[k].iConjunto == iConjuntoAlias )
circulos[k].iConjunto = circulos[i].iConjunto;
} else { // j no pertenece todavía a ningún grupo
// El círculo j pasa a ser del grupo del círculo i
circulos[j].iConjunto = circulos[i].iConjunto;
}
}
}
}
// Apertura del fichero para escritura
std::ofstream outFich(nombreFichO.c_str(),
std::ios::out |std::ios::trunc);
if (!outFich) {
std::cout << "ERROR al abrir fichero"
<< nombreFichO << std::endl;
return 1;
}
// Cuenta el número de elementos de cada conjunto y salida
for (int iC=1; iC<nConjunto; iC++) {
int nElem = 0;
for (int i=0; i<circulos.size(); i++ )
if ( circulos[i].iConjunto == iC )
nElem++;
if ( nElem > 0 )
outFich << nElem << std::endl;
}
outFich.close();
return 0;
Código 1.4: Solución al Ejercicio 3 (parte final).
Dpto. de Informática y Automática, UNED
9
LENGUAJES DE PROGRAMACIÓN
EJERCICIO 4
Escriba un programa en C++ que calcule la frecuencia con la que aparece cada
número de un determinado conjunto de números naturales.
Por ejemplo, dado el conjunto {2, 1, 1, 2, 4, 1, 1, 1}, el programa debe obtener que
la frecuencia del número 1 es 5/8 (cinco de los ocho números tienen valor 1),
la frecuencia del número 2 es 2/8 (dos de los ocho números tienen valor 2) y la
frecuencia del número 4 es 1/8 (uno de los ocho números tiene valor 4).
El conjunto de números naturales se encuentra almacenado en un fichero de texto
llamado nElemConj.txt. Los números están escritos formando una única columna.
El programa debe leer el contenido del fichero, calcular la frecuencia de cada
número natural, mostrar el resultado en la consola y terminar.
El resultado debe mostrarse en dos columnas: en la primera los números, ordenados crecientemente, y en la segunda su frecuencia, expresada como fracción. En
el ejemplo anterior, la salida del programa debería ser:
1 5/8
2 2/8
4 1/8
Solución al Ejercicio 4
// Fichero: histograma.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
const std::string nombreFichI = "nElemConj.txt";
struct barraHistograma {
int valor;
int numVecesAparece;
};
Código 1.5: Solución al Ejercicio 4 (parte inicial).
10
Dpto. de Informática y Automática, UNED
SOLUCIÓN AL TRABAJO PRÁCTICO - JUNIO DE 2015
int main() {
// Apertura del fichero para lectura
std::ifstream inFich(nombreFichI.c_str(), std::ios::in);
if (!inFich) {
std::cout << "ERROR al abrir fichero "
<< nombreFichI << std::endl;
return 1;
}
// Lectura del fichero y cálculo frecuencia
std::vector<barraHistograma> hist;
int numTotalValores = 0;
while ( !inFich.eof() ) {
int num;
inFich >> num;
if (inFich.eof()) break;
numTotalValores++;
bool encontrado = false;
for ( int i=0; !encontrado && i<hist.size(); i++ ) {
if ( hist[i].valor == num ) {
hist[i].numVecesAparece++;
encontrado = true;
}
}
if ( !encontrado ) {
barraHistograma bh = { num, 1 };
hist.push_back(bh);
}
}
inFich.close();
if ( hist.size() > 1 ) { // Ordenación del vector y salida
bool desordenado = true;
while (desordenado) {
desordenado = false;
for (int i=0; i<hist.size()-1; i++) {
if ( hist[i].valor > hist[i+1].valor ) {
desordenado = true;
barraHistograma bh = hist[i+1];
hist[i+1] = hist[i];
hist[i] = bh;
}
}
}
for (unsigned int i=0; i<hist.size(); i++)
std::cout << hist[i].valor << "\t"<<
hist[i].numVecesAparece << "/"<<
numTotalValores << std::endl;
} else {
std::cout << "El fichero no contiene numeros"
<< std::endl;
}
return 0;
}
Código 1.6: Solución al Ejercicio 4 (parte final).
Dpto. de Informática y Automática, UNED
11
Descargar