Advertisement
ahorsewithnoname

Tarea4

Jan 14th, 2022
50
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 13.27 KB | None | 0 0
  1. /* Equipo V_05
  2.  
  3.     Santiago Puyol
  4.  
  5.     Nicolás Ubieto
  6.  
  7.     Borja Zapata
  8.  
  9. */
  10.  
  11. #include <iostream>
  12. #include <cstdio>
  13. #include <cmath>
  14. #include <string.h>
  15.  
  16. #define MAXFONDOS 20
  17. #define MAXOPERACIONES 100
  18. #define MAX_CHAR 100
  19.  
  20. using namespace std;
  21.  
  22. /** Representa una fecha */
  23. struct fecha
  24. {
  25.     int dia, mes, agno;
  26. };
  27. typedef struct fecha Fecha;
  28.  
  29.  
  30. /** Representa una operación de compra o venta
  31.     de un cierto número de participaciones del fondo
  32.     cuyo identificador se almacena en el campo 'idFondo'. El número
  33.     de unidades (participaciones) es positivo si la operación
  34.     es una compra; es negativo si se trata de un venta.
  35.     El campo 'precioUnidad' es el precio de compra/venta
  36.     de cada participación en esta operación.
  37.     El valor de la operación es el resultado, positivo
  38.     o negativo, de multiplicar el número de participaciones
  39.     por su precio.
  40. */
  41. struct operacion
  42. {
  43.     int idFondo;
  44.     Fecha fechaOperacion;
  45.     double unidades, precioUnidad;
  46. };
  47. typedef struct operacion Operacion;
  48.  
  49.  
  50. /** Representa un fondo de inversión
  51.     cuyo identificador se almacena en el campo 'idFondo'.
  52.     El nombre del fondo está en el campo 'nombreFondo'.
  53.     El campo 'precio' es el precio de cada participación del fondo
  54.     en la fecha 'fechaReferencia'
  55. */
  56. struct fondo
  57. {
  58.     int idFondo;
  59.     double precio;
  60.     Fecha fechaReferencia;
  61.     char nombreFondo[MAX_CHAR];
  62. };
  63. typedef struct fondo Fondo;
  64.  
  65.  
  66. /** Representa una función cuya expresión analítica
  67.     es la suma de una colección de términos de la forma
  68.     C·z^t. El coeficiente C y el exponente t del término
  69.     i-ésimo se almacenan en las correspondientes
  70.     componentes de los arrays 'coeficiente' y 'exponente'.
  71. */
  72. struct funcion
  73. {
  74.     int nTerminos;
  75.     double coeficiente[MAXOPERACIONES+1];
  76.     double exponente[MAXOPERACIONES+1];
  77. };
  78. typedef struct funcion Funcion;
  79.  
  80.  
  81. /** Representa el nombre de un fondo junto
  82.     con su TIR en una determinada fecha.
  83. */
  84. struct tirFondo
  85. {
  86.     Fecha fecha;
  87.     char fondo[MAX_CHAR];
  88.     double tir;
  89. };
  90. typedef struct tirFondo TirFondo;
  91.  
  92.  
  93. /** Determina si un año es o no bisiesto.
  94.  
  95.     Entradas: un entero (a>1700), el año (parámetro dato)
  96.     Salidas:  true si y sólo si a representa un
  97.         año bisiesto en el calendario gregoriano
  98.         (resultado de la función).
  99. */
  100. bool esBisiesto(int a);
  101.  
  102.  
  103. /** Calcula el número de días de un año. Esto es,
  104.     devuelve 366 si el año es bisiesto y 365 en otro caso.
  105.  
  106.     Entradas: un entero (a>1700), el año (parámetro dato)
  107.     Salidas:  un entero, el número de días del año a
  108.         según el calendario gregoriano (resultado de función).
  109. */
  110. int diasAgno(int a);
  111.  
  112.  
  113. /** Calcula el número de días de un mes en un año dado.
  114.  
  115.     Entradas: dos enteros, 1<=m<=12 (el mes) y a>1700 el año.
  116.         (parámetros dato)
  117.     Salidas:  un entero, el número de días del mes m en el
  118.         año a según el calendario gregoriano (res. de función).
  119. */
  120. int diasMes(int m, int a);
  121.  
  122.  
  123. /** Dada una fecha, calcula la fracción de año que ha transcurrido
  124.     desde el comienzo del año hasta las 00:00:00 horas del día
  125.     que representa la fecha. Esto es, el número real (entre 0 y 1)
  126.     que resulta al dividir el número de días desde el principio de
  127.     año hasta el día de la fecha dividido por el número total de días
  128.     del año.
  129.  
  130.     Entradas: una fecha válida (parámetro dato).
  131.     Salidas:  un real, la fracción de año transcurrida hasta la fecha
  132.         (resultado de función).
  133. */
  134. double fraccionAgno(Fecha f);
  135.  
  136.  
  137. /** Calcula el número de años transcurridos entre dos fechas.
  138.  
  139.     Entradas: dos fechas, f1 y f2, tales que f1 es anterior a f2
  140.         (parámetros dato).
  141.     Salidas:  un real, el número de años transcurridos entre las
  142.         dos fechas (resultado de función).
  143. */
  144. double agnosEntreDosFechas(Fecha f1, Fecha f2);
  145.  
  146.  
  147. /** Dadas dos fechas, este subalgoritmo devuelve
  148.     -1 si la primera es anterior a la segunda
  149.     0 si las fechas son iguales y
  150.     1 si la primera es posterior a la segunda.
  151.  
  152.     Entradas: dos fechas (parámetro dato)
  153.     Salidas:  un entero, indicando cual es anterior (res. función).
  154. */
  155. int fechaAnterior(Fecha f1, Fecha f2);
  156.  
  157.  
  158. /** Dada una operación de compra/venta de unidades de un fondo,
  159.     calcula el valor de la operación, que será
  160.     positivo si se trata de una compra y negativo si es una venta.
  161.  
  162.     Entradas: una operación (parámetro dato)
  163.     Salidas:  un real, el precio total de la operación (res. función).
  164. */
  165. double calculaCapital(Operacion o);
  166.  
  167.  
  168. /** Evalúa una función, representada por un dato de tipo Función,
  169.     en un punto x.
  170.  
  171.     Entradas: una función, f, y un real x (parámetros dato)
  172.     Salidas:  el real f(x)  (resultado de función).
  173. */
  174. double evaluaFuncion(double x, Funcion f);
  175.  
  176.  
  177. /** Dado un dato de tipo Funcion, calcula una de sus raíces en el
  178.     intervalo [0,3].
  179.  
  180.     Entradas: un dato, f, de tipo Funcion (parámetro dato)
  181.     Salidas:  un real en el intervalo [0,3] que es raíz de f
  182.         (resultado de función).
  183. */
  184. double calculaTIR(Funcion f);
  185.  
  186.  
  187. /** Dado un puntero f a una estructura de tipo FILE que apunta a un fichero
  188.     de texto tipo fFondo abierto para lectura, lee la información necesaria
  189.     para construir un dato de tipo Fondo.
  190.  
  191.     Entradas: un dato, f, de tipo puntero a FILE
  192.     Salidas: un dato de tipo Fondo construido a partir de la información
  193.         del fichero (resultado de función)
  194. */
  195. Fondo leeFondo(FILE* f);
  196.  
  197.  
  198. /** Dado un array de registros de tipo TirFondo así
  199.     como su número de componentes, devuelve ese mismo
  200.     array ordenado en orden creciente de fecha
  201.  
  202.     Entradas: un array de datos de tipo TirFondo y un entero que representa
  203.         el número de datos almacenados en el array.
  204.     Salidas: el mismo array de tipo TirFondo, ordenado en orden creciente de
  205.         fecha.
  206. */
  207. void ordenaCrecientePorFecha(TirFondo arrTIR[], int nComponentes);
  208.  
  209.  
  210. int main()
  211. {
  212.     //Variables relacionadas con los ficheros
  213.     FILE* fich1;
  214.     FILE* fich2;
  215.     FILE* fichsalida;
  216.     char nfs[MAX_CHAR], nf1[MAX_CHAR], nf2[MAX_CHAR];
  217.  
  218.     //Variables auxiliares (para comparar datos)
  219.     Fondo auxFond;
  220.     double auxTIR = 0;
  221.     Operacion auxOper = {0};
  222.     Funcion auxFun = {0};
  223.    
  224.     //Contadores o índices
  225.     double totalParts = 0;
  226.     int fondoIndex = 0;
  227.  
  228.     //El array de salida, es lo que devolveremos con los tirs ordenados
  229.     TirFondo tirs[MAXFONDOS];
  230.    
  231.     printf("Introduce a continuacion el nombre del fichero de fondos: ");
  232.     scanf("%s", nf1);
  233.  
  234.     printf("\nAhora introduce el nombre del fichero de operaciones: ");
  235.     scanf("%s", nf2);
  236.  
  237.     fich1 = fopen(nf1,"r");
  238.  
  239.     if(fich1 == NULL){
  240.         printf("Ha habido un problema con la apertura del fichero de fondos.");
  241.     }
  242.     else{
  243.         fich2 = fopen(nf2,"rb");
  244.         if(fich2 == NULL){
  245.             printf("Ha habido un problema con la apertura del fichero de operaciones.");
  246.         }
  247.         else{
  248.             auxFond = leeFondo(fich1);
  249.  
  250.             fread(&auxOper,sizeof(Operacion),1,fich2);
  251.             do{
  252.                 //Ponemos las variables auxiliares a 0 (cada iteración del bucle
  253.                 //mayor es un fondo distinto)
  254.                 totalParts = 0;
  255.                 auxTIR = 0;
  256.                 auxFun.nTerminos = 0;
  257.                 for(int i = 0; i < MAXOPERACIONES + 1; i++){
  258.                     auxFun.exponente[i] = 0;
  259.                     auxFun.coeficiente[i] = 0;
  260.                 }
  261.  
  262.                 //Leemos los datos de la operación a procesar
  263.                
  264.                 do{
  265.                     //Nota: podemos usar un do-while porque hemos asumido que hay al menos 1 operación de cada fondo, si no
  266.                     //no podríamos saber si la 1º corresponde al primer fondo
  267.  
  268.                     auxFun.coeficiente[auxFun.nTerminos] = calculaCapital(auxOper);
  269.                     auxFun.exponente[auxFun.nTerminos] = agnosEntreDosFechas(auxOper.fechaOperacion,auxFond.fechaReferencia);
  270.  
  271.                     //Necesitamos un contador de las unidades totales para sacar el valor final
  272.                     totalParts += auxOper.unidades;
  273.  
  274.                     auxFun.nTerminos++;
  275.  
  276.                     fread(&auxOper,sizeof(Operacion),1,fich2);
  277.                 }while(auxOper.idFondo == auxFond.idFondo && !feof(fich2));
  278.  
  279.                 auxFun.coeficiente[auxFun.nTerminos] = -1 * totalParts * auxFond.precio;
  280.                 auxFun.nTerminos++;
  281.  
  282.                 auxTIR = calculaTIR(auxFun);
  283.                 tirs[fondoIndex].fecha = auxFond.fechaReferencia;
  284.                 strcpy(tirs[fondoIndex].fondo,auxFond.nombreFondo);
  285.                 tirs[fondoIndex].tir = auxTIR;
  286.  
  287.                 fondoIndex++;
  288.  
  289.                 auxFond = leeFondo(fich1);
  290.             }while(!feof(fich1));
  291.  
  292.             ordenaCrecientePorFecha(tirs,fondoIndex);
  293.  
  294.             printf("Introduce ahora el nombre del fichero de salida (es un fichero de texto): ");
  295.             scanf("%s",nfs);
  296.  
  297.             //Este pequeño bloque hace que la extensión del archivo de salida
  298.             //siempre sea txt. Si los ultimos 4 caracteres de la cadena no son
  299.             //".txt" concatena el ".txt"
  300.  
  301.             char auxSub[5];
  302.             if(strcmp(strcpy(auxSub, nfs + strlen(nfs) - 4), ".txt") != 0) strcat(nfs,".txt");
  303.            
  304.             fichsalida = fopen(nfs,"w");
  305.             if(fichsalida == NULL){
  306.                 printf("No se ha podido abrir el fichero de salida.");
  307.             }
  308.             else{
  309.                 for(int i = 0; i < fondoIndex; i++){
  310.                     fprintf(fichsalida,"%02i/%02i/%04i %+.4lf %s",tirs[i].fecha.dia,tirs[i].fecha.mes,tirs[i].fecha.agno,tirs[i].tir,tirs[i].fondo);
  311.                 }
  312.                 fclose(fichsalida);
  313.             }
  314.             fclose(fich2);
  315.         }
  316.     }
  317.     fclose(fich1);
  318. }
  319.  
  320.  
  321. /** Determina si un año es o no bisiesto.
  322. */
  323. bool esBisiesto(int a)
  324. {
  325.     return (a%400==0) || (a%4==0 && a%100!=0);
  326. }
  327.  
  328.  
  329. /** Calcula el número de días de un año. Esto es,
  330.     devuelve 366 si el año es bisiesto y 365 en otro caso.
  331. */
  332. int diasAgno(int a)
  333. {
  334.     if(esBisiesto(a)) return 366;
  335.     else return 365;
  336. }
  337.  
  338.  
  339. /** Calcula el número de días de un mes en un año dado.
  340. */
  341. int diasMes(int m, int a)
  342. {
  343.     switch(m)
  344.     {
  345.     case 2:
  346.         if (esBisiesto(a)) return 29;
  347.         else return 28;
  348.     case 4:
  349.     case 6:
  350.     case 9:
  351.     case 11:
  352.         return 30;
  353.     default:
  354.         return 31;
  355.     }
  356. }
  357.  
  358.  
  359. /** Dada una fecha, calcula la fracción de año que ha transcurrido
  360.     desde el comienzo del año hasta el día que representa la fecha.
  361.     Esto es, el número real (entre 0 y 1) que resulta al dividir
  362.     el número de días desde el principio de año hasta el día de la
  363.     fecha dividido por el número total de días del año.
  364. */
  365. double fraccionAgno(Fecha f)
  366. {
  367.     double dias=f.dia-1;
  368.     for(int i=1; i<f.mes; i++)
  369.     {
  370.         dias=dias+diasMes(i,f.agno);
  371.     }
  372.     return dias/diasAgno(f.agno);
  373. }
  374.  
  375.  
  376. /** Calcula el número de años transcurridos entre dos fechas.
  377. */
  378. double agnosEntreDosFechas(Fecha f1, Fecha f2)
  379. {
  380.     return f2.agno-f1.agno+fraccionAgno(f2)-fraccionAgno(f1);
  381. }
  382.  
  383.  
  384. /** Determina si una fecha es anterior a otra
  385. */
  386. int fechaAnterior(Fecha f1, Fecha f2)
  387. {
  388.     double diferencia=agnosEntreDosFechas(f1,f2);
  389.     if (diferencia>0) return -1;
  390.     else if(diferencia==0) return 0;
  391.     else return 1;
  392. }
  393.  
  394.  
  395. /** Dada una operación de compra/venta de unidades de un producto
  396.     financiero, calcula el valor de la operación, que será
  397.     positivo si se trata de una compra y negativo si es una venta.
  398. */
  399. double calculaCapital(Operacion o)
  400. {
  401.     return o.precioUnidad*o.unidades;
  402. }
  403.  
  404.  
  405. /** Evalúa una función, representada por un dato de tipo Función,
  406.     en un punto x.
  407. */
  408. double evaluaFuncion(double x, Funcion f)
  409. {
  410.     double b=0;
  411.     for(int j=0; j<f.nTerminos; j++)
  412.         b=b+f.coeficiente[j]*pow(x,f.exponente[j]);
  413.     return b;
  414. }
  415.  
  416.  
  417. /** Dado un dato de tipo Funcion, calcula una de sus raíces en el
  418.     intervalo [0,3].
  419. */
  420. double calculaTIR(Funcion f)
  421. {
  422.     double inf = 0, fin = 3;
  423.     const double eps = 1.0e-12;
  424.  
  425.     while (fin-inf>eps)
  426.     {
  427.         double med = (inf+fin)/2;
  428.         double valor = evaluaFuncion(med, f);
  429.         if (valor<0) inf = med;
  430.         else if (valor>0) fin = med;
  431.         else inf = fin = med;
  432.     }
  433.     return ((inf+fin)/2-1)*100;
  434. }
  435.  
  436.  
  437. Fondo leeFondo(FILE* f){
  438.     Fondo fnd = {0};
  439.     fscanf(f,"%i %i %i %i %lf \\n",&fnd.idFondo, &fnd.fechaReferencia.dia,
  440.                                    &fnd.fechaReferencia.mes, &fnd.fechaReferencia.agno, &fnd.precio);
  441.     fgets(fnd.nombreFondo,MAX_CHAR,f);
  442.     return fnd;
  443. }
  444.  
  445. void ordenaCrecientePorFecha(TirFondo arrTIR[], int nComponentes){
  446.     //Se ordenan por el ordenamiento de burbuja, aunque no es el más
  447.     //eficiente la diferencia de eficiencia resulta despreciable dado un MAXFONDOS de 20
  448.    
  449.     TirFondo auxTIR;
  450.    
  451.     for(int i = 0 ; i <= nComponentes - 1; i++){
  452.         for(int j = 0; j < nComponentes - 1 - i; j++){
  453.             if(fechaAnterior(arrTIR[j].fecha,arrTIR[j+1].fecha) == 1){
  454.                 auxTIR = arrTIR[j];
  455.                 arrTIR[j] = arrTIR[j+1];
  456.                 arrTIR[j+1] = auxTIR;
  457.             }
  458.         }
  459.     }
  460. }
  461.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement