Ejercicio obligatorio 2
Fecha de entrega: Lunes 4 de mayo
Nota
Nunca es buena idea empezar por un ejercicio integrador antes de tener practicados los temas que el trabajo integra.
Se sugiere antes de desarrollar este trabajo resolver, al menos, los siguientes ejercicios de la guía de Memoria dinámica:
Ejercicio 12 (combinar vectores).
Ejercicio 14.a (matriz identidad).
Ejercicio 16 con el 1.b y 1.c de la guía de estructuras (dirección y persona).
Introducción
Queremos modelar una matriz, para ello definimos la estructura:
typedef struct {
float *m;
size_t filas, columnas;
} matriz_t;
que permite almacenar en memoria una matriz según el siguiente esquema:
Trabajo
Creación y destrucción
Se pide implementar una función auxuliar
matriz_t *_matriz_crear(size_t n, size_t m); que genere la memoria
necesaria para almacenar una matriz de n x m valores. Los valores no deben
ser inicializados. La función debe devolver la matriz creada o NULL en
caso de falla.
Se pide implementar la función void matriz_destruir(matriz_t *matriz);
que libere la memoria asociada a la matriz previamente creada.
Acceso a los datos
Se pide implementar una función
size_t matriz_filas(const matriz_t *matriz); que devuelva el número de
filas de la matriz.
Se pide implementar una función
size_t matriz_columnas(const matriz_t *matriz); que devuelva el número
de columnas de la matriz.
Se pide implementar una función
void matriz_dimensiones(const matriz_t *matriz, size_t *filas, size_t *columnas);
que devuelva por la interfaz la cantidad de filas y de columnas de la
matriz.
Se pide implementar una función
float matriz_obtener(const matriz_t *matriz, size_t fila, size_t columna);
que devuelva el valor almacenado en la posición fila, columna de la
matriz.
Se pide implementar una función
void matriz_establecer(matriz_t *matriz, size_t fila, size_t columna, float valor);
que establezca el valor en la posición fila, columna de la matriz.
Nota
Siendo que la matriz está linealizada en el arreglo, en principio no puede accederse con sintaxis de doble corchete.
Ahora bien, si el arreglo se asigna sobre un puntero de tipo
float (*m)[columnas] puede utilizarse m como una matriz.
Es indistinto para este trabajo si se elige sintaxis de vectores o de matrices para acceder a los elementos individuales.
Creación de matrices
Implementar una función matriz_t *matriz_crear_mn(size_t n); que
devuelva una matriz \(M^n\) como la de la función inicializar() del EJ1.
Implementar una función matriz_t *matriz_crear_mc(double ac); que
devuelva una matriz \(M_c\) como la siguiente:
Implementar una función matriz_t *matriz_crear_mb(double ab); que
devuelva una matriz \(M_b\) como la siguiente:
Implementar una función
matriz_t *matriz_crear_mt(const float vector[3]); que dado un vector
\((x, y, z)\) devuelva una matriz \(M_t\) como la siguiente:
Nota
Notar que las cuatro matrices pedidas son muy similares a la matriz identidad, tal vez tenga sentido desarrollar una función auxiliar que cree una matriz identidad y luego modificar los valores que difieren de ella.
Multiplicación de matrices
Implementar una función
matriz_t *matriz_multiplicar(const matriz_t *a, const matriz_t *b);
que devuelva \(A\times B\). En caso de falla o de no ser compatibles las
matrices recibidas debe devolver NULL.
Aplicar
Implementar una función
matriz_t *matriz_aplicar(const matriz_t *matriz, const matriz_t *ps);.
La matriz es una matriz de \(4\times4\) mientras que ps es de \(n\times3\).
Cada una de las filas de ps es un vector p como los de la función
aplicar_vector() del EJ1. La función debe aplicar la matriz en cada uno de
los p, según las fórmulas del EJ1, y devolver una matriz de \(n\times2\) con
cada uno de los vectores aplicados, quedándose sólo con las dos primeras columnas,
o sea, las componentes \((x, y)\), ya sabemos que \(z = -1\) y podemos
descartarlo.
Agregar fila
Implementar una función
bool matriz_agregar_fila(matriz_t *matriz, float fila[]); que agregue
una nueva fila en la matriz. Se asume que la fila tiene
matriz->columnas elementos. La función debe devolver true si puede realizar
la acción y false en caso contrario.
Programa
Implementar un programa que primero cree una matriz \(M = M^4 \times M_c \times M_t \times M_b\) con \(a_c = 0.1\), \(a_b = 0.3\) y el vector de \(M_t\) como \((0, 0, -50)\). (Mismos parámetros que el EJ1, para sorpresa de nadie.)
Luego que lea de stdin coordenadas de vectores en \(\mathbb R^3\) de a
una por vez y las vaya almacenando en una matriz por filas.
Finalmente que aplique la matriz \(M\) a esos vectores e imprima sus
coordenadas \(x, y\) por stdout.
La salida tendrá que ser exactamente igual a la del EJ1 para los mismos datos de entrada.
La matriz \(M\) debería dar
{{0.950564, -0.099833 ,0.294044, 0.000000}, {0.095375, 0.995004, 0.029503, 0.000000}, {-0.295520, 0.000000, 0.955337, -50.000000}, {0.295520, 0.000000, -0.955337, 50.000000}}.
Entrega
Deberá entregarse el código fuente del programa desarrollado.
El programa debe:
Compilar correctamente con los flags:
-Wall -Werror -std=c99 -pedantic -fno-extended-identifiers
y pasar Valgrind correctamente
La entrega se realiza a través del sistema de entregas.
El ejercicio es de entrega individual.