Problemas de Programación 1 Grado en Ingenierı́a Informática Miguel Ángel Latre y Javier Martı́nez Área de Lenguajes y Sistemas Informáticos Departamento de Informática e Ingenierı́a de Sistemas Curso 2017-18 Índice general 1. Sintaxis expresada mediante reglas BNF 1.1. Reglas sintácticas para la escritura de literales numéricos 3 . . . . . . . . . . . . . 3 1.2. Reglas sintácticas para la escritura de identificadores . . . . . . . . . . . . . . . . 4 1.3. Reglas sintácticas para la escritura de expresiones aritméticas . . . . . . . . . . . 5 1.4. Reglas sintácticas para la escritura de expresiones de relación y lógicas . . . . . . 6 1.5. Reglas sintácticas para la escritura de instrucciones . . . . . . . . . . . . . . . . . 7 1.6. Reglas sintácticas para la escritura de algunos tipos de datos . . . . . . . . . . . 8 2. Escritura de expresiones aritméticas y lógicas 10 2.1. Escritura de expresiones aritméticas . . . . . . . . . . . . . . . . . . . . . . . . . 10 2.1.1. Escritura de expresiones aritméticas cuyo resultado es un número entero . 10 2.1.2. Escritura de expresiones aritméticas cuyo resultado es un número real . . 11 2.2. Escritura de expresiones lógicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 3. Trabajo con datos enteros 14 3.1. Diseño de funciones para gestionar fechas del calendario . . . . . . . . . . . . . . 4. Trabajo con datos reales 14 17 4.1. Cálculo de magnitudes geométricas de polı́gonos regulares . . . . . . . . . . . . . 17 4.2. Caracterización de la caida libre de un sólido rı́gido . . . . . . . . . . . . . . . . . 18 4.3. Caracterización de un tiro parabólico . . . . . . . . . . . . . . . . . . . . . . . . . 18 4.4. Amortización de un préstamo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 1 Presentación La temática de los problemas de esta colección está centrada en las primeras lecciones del curso. Posteriormente, en las diferentes prácticas de la asignatura, se propondrá la resolución de un buen número de problemas de programación relacionados con las restantes lecciones del curso. No es un secreto que a programar se aprende programando. Quien asista a las clases de Programación 1 y estudie las notas del curso puede llegar a comprender los conceptos en los que se basa el trabajo de un programador, conocerá la tecnologı́a disponible y también las metodologı́as que conviene aplicar en cada caso. No obstante, para que conceptos, tecnologı́a y metodologı́as rindan lo esperado es esencial que cada estudiante adquiera una experiencia suficiente en programación. Para ello deberá aplicar lo estudiado a la resolución de problemas tales como los que se proponen en esta colección o en el programa de prácticas de la asignatura. Saber resolver los problemas de programación de esta colección constituye la mejor garantı́a de que el aprendizaje progresa adecuadamente. Cada estudiante ha de ser capaz de resolverlos en primera instancia con lápiz y papel . En aquellos problemas en los que se exija el diseño de código, que son la mayorı́a de los que se propongan a lo largo del curso, es necesario que el alumno complete el trabajo programando su solución en un computador. Ambas tareas, el trabajo con lápiz y papel y la programación en el computador, son complementarias y esenciales en el estudio de un curso de programación. En la sección de Materiales Docentes Comunes de la web de la asignatura Programación 1 se ha dispuesto un enlace para acceder a algunos ficheros con código C++ que facilitan el trabajo de quienes resuelvan estos problemas. Zaragoza, Septiembre de 2017 Miguel Ángel Latre y Javier Martı́nez Departamento de Informática e Ingenierı́a de Sistemas de la Universidad de Zaragoza 2 Capı́tulo 1 Sintaxis expresada mediante reglas BNF 1.1. Reglas sintácticas para la escritura de literales numéricos En este problema se va a pedir la escritura de reglas sintácticas que determinen cómo han de ser escritos los siguientes sı́mbolos de un lenguajes ficticio de programación: Un dı́gito. Un dı́gito es cada uno de los diez caracteres que representan una cifra escrita en base 10, es decir: 0, 1, 2, . . . , 8 y 9. Un natural. Un natural se escribe como una secuencia de uno o más dı́gitos. Ejemplos de naturales: 0, 7, 007, 11, 606, 1000, 98707 y 82672651. Un signo. Un signo viene determinado por uno de los dos caracteres siguientes: + y -. Un exponente. La escritura de un exponente comienza por una E o una e. Le sigue un valor numérico natural, con o sin signo. Ejemplos: E0, e7, E-7, E07, e-07, e1075, E-23. Un número real sin signo. Un número real sin signo se representa, en primer lugar, escribiendo su parte entera, un número natural. Le sigue, opcionalmente, su parte decimal (un número natural) precedida por un punto. A continuación, también opcionalmente, un exponente. Ejemplos de números reales sin signo: 34, 0, 34.045, 0.0012, 1045.4, 34E-4, 0.1165E12. En cambio, las siguientes secuencias de caracteres no definirán números reales sin signo válidos: 34., .045, 34.E5 y .045E12. Un literal entero se representa como un número natural que, opcionalmente, puede venir precedido por un signo + o -. Ejemplos: 1207, +1207 y -1207. Un literal real se representa como un número real sin signo que, opcionalmente, puede venir precedido por un signo + o -. Ejemplos: 13.166, +13.166, -13.166, 0.18E-6, +0.18E-6 y -0.18E-6. A partir de las definiciones anteriores se deben escribir reglas sintácticas para cada uno de los sı́mbolos definidos. En la definición de cualquiera de las reglas sintácticas se puede hacer uso de otras reglas sintácticas definidas previa o posteriormente en este documento. En cualquier momento se pueden definir reglas sintácticas complementarias a las que se enuncian a continuación para facilitar la escritura de éstas. 3 <dı́gito> ::= ... <natural> ::= ... <signo> ::= ... <exponente> ::= ... <real_sin_signo> ::= ... <literal_entero> ::= ... <literal_real> ::= ... 1.2. Reglas sintácticas para la escritura de identificadores Deben escribirse las reglas sintácticas que determinen cómo han de ser escritos los siguientes elementos de un lenguaje ficticio de programación: Una minúscula. Consideraremos minúsculas cada una de las letras minúsculas del alfabeto inglés, es decir: a, b, c, . . . , x, y y z. No van a ser consideradas como minúsculas ni las vocales minúsculas con tı́lde ni letras no presentes en el alfabeto inglés como la ~ n, la ç, etc. Una mayúscula. Consideraremos mayúsculas cada una de las letras mayúsculas del alfabeto inglés, es decir: A, B, C, . . . , X, Y y Z. No van a ser consideradas como mayúsculas ni las vocales mayúsculas con tı́lde ni letras no presentes en el alfabeto inglés como la ~ N, la Ç, etc. Una letra. Consideraremos letras cualquier carácter que sea o bien una minúscula o bien una mayúscula. Un identificador. La escritura de un identificador, en el lengujae que estamos definiendo, ha de comenzar obligatoriamente por una letra pudiendo, en su caso, ir seguida por una secuencia de letras o dı́gitos, en cualquier orden. Ejemplos de identificadores válidos: cuenta, Cuenta, x, x027, x33nuevo, DIM, primerIndice. A partir de las definiciones anteriores se deben escribir reglas sintácticas para cada uno de los sı́mbolos definidos. En la definición de cualquiera de las reglas sintácticas se puede hacer uso de otras reglas sintácticas definidas previa o posteriormente en este documento. También se pueden definir reglas sintácticas complementarias a las que se enuncian a continuación para facilitar la escritura de éstas. <minúscula> ::= <mayúscula> ::= ... ... <letra> ::= ... <identificador> ::= ... 4 1.3. Reglas sintácticas aritméticas para la escritura de expresiones Las reglas sintácticas que se definen a continuación contribuyen a definir la sintaxis de cualquier expresión aritmética en el lenguaje que se está definiendo. <literal_numérico_sin_signo> ::= <natural> | <real_sin_signo> <término> ::= <factor> { <operador_de_factores> <operador_de_factores> ::= <factor> } "*" | "/" <factor> ::= [ <signo> ] ( <identificador> | <literal_numérico_sin_signo> | ( "(" <expresión_numérica> ")" ) <operador_de_términos> ::= "+" | "-" <expresión_numérica> ::= <término> { <operador_de_términos> <término> } Se pide, en primer lugar, rellenar esta tabla escribiendo un SI o un NO en cada una de sus casillas. Cada fila está asociada a la secuencia de caracteres escrita en su primera columna. las restantes columnas representan una categorı́a sintáctica: (factor, término o expresión numérica). Se debe escribir un cada casilla un SI en el caso de que la secuencia de caracteres defina un elemento sintácticamente válido en la categorı́a que corresponde a la columna y un NO en el caso contrario. Secuencia de caracteres x y x + y z 1 x x + y - z + 1 factor término expresión numérica Se pide, en segundo lugar, rellenar esta tabla escribiendo un SI o un NO en cada una de sus casillas. Cada fila está asociada a la secuencia de caracteres escrita en su primera columna. Cada columna representa una categorı́a sintáctica (factor, término o expresión numérica. Escribir en cada casilla un SI en el caso de que la secuencia de caracteres defina un elemento sintácticamente válido en la categorı́a que corresponde a la columna y un NO en el caso contrario. Secuencia de caracteres a b a + b (a + b) a - b (a - b) 2.0 (a+b)*(a-b)/2.0 factor 5 término expresión numérica 1.4. Reglas sintácticas para la escritura de expresiones de relación y lógicas Las reglas sintácticas que se definen a continuación contribuyen a definir la sintáxis de cualquier expresión de relación y de cualquier expresión lógica en el lenguaje que se está definiendo. <literal_cierto> ::= "cierto" | "CIERTO" <literal_falso> ::= "falso" | "FALSO" <literal_booleano> ::= <literal_cierto> | <literal_falso> <operador_relación> ::= "==" | "!=" | ">" | ">=" | "<" | "<=" <expresión_relación> ::= <expresión_numérica> <expresión_numérica> <operador_relación> <operador_lógico_negación> ::= "NOT" <operador_conjuntivo> ::= "AND" <operador_disyuntivo> ::= "OR" <operando_lógico> := [ <operador_lógico_negación> ] ( <identificador> | <literal_booleano> | <expresión_relación> | ( "(" <expresión_lógica> ")" ) ) <operando_lógico_conjuntivo> := <operando_lógico> { <operador_conjuntivo> <operando_lógico> <expresión_lógica> ::= { <operando_lógico_conjuntivo> <operador_disyuntivo> <operando_lógico_conjuntivo> } } Se pide, en primer lugar, rellenar la tabla que sigue escribiendo un SI o un NO en cada una de sus casillas. Debe escribirse un SI en una casilla en el caso de que la secuencia de caracteres defina un elemento sintácticamente válido en la categorı́a que corresponde a la fila y un NO en caso contrario. Categorı́a sintáctica expresión relación operando lógico operando lógico conjuntivo expresión lógica a>=0 a<MAX a>=0 AND a<MAX a>=0 AND a<MAX OR a==x Se pide, en segundo lugar, rellenar la tabla que sigue escribiendo un SI o un NO en cada una de sus casillas. Escribir un cada casilla un SI en el caso de que la secuencia de caracteres defina un elemento sintácticamente válido en la categorı́a que corresponde a la fila y un NO en el caso contrario. 6 a Categorı́a sintáctica expresión relación operando lógico operando lógico conjuntivo expresión lógica 1.5. NOT a x<y NOT a AND x<y Reglas sintácticas para la escritura de instrucciones <instrucción> ::= <instrucción_simple> | <instrucción_compuesta> <instrucción_simple> ::= [ <asignación> | <invocación> | <devolución> ] <expresión> ::= <expresión_numérica> | <asignación> ::= <identificador> ":=" <invocación> ::= <identificador> "(" [ <devolución> ::= "devuelve" <instrucción_compuesta> ::= ";" <expresión_lógica> <expresión> <argumento> { "," <argumento> } ] ")" <expresión> <bloque_secuencial> | <instrucción_condicional> | <instrucción_iterativa> <bloque_secuencial> := "principio" { <instrucción> } "fin" <instrucción_condicional> := "si" <expresión_lógica> "entonces" <instrucción> { "sino si" <expresión_lógica> "entonces" <instrucción> } [ "sino" <instrucción> ] "finSi" <instrucción_iterativa> := "mientrasQue" <expresión_lógica> "hacer" <instrucción> "finMQ" Se pide escribir tres secuencias de sı́mbolos diferentes que respondan a la sintaxis de cada una de las categorı́as sintácticas que se enumeran a continuación. Debe procurarse escribir tres secuencias con las máximas diferencias sintácticas entre sı́. instrucción: escribir tres instrucciones instrucción simple: escribir tres instrucciones simples asignación: escribir tres instrucciones de asignación invocación: escribir tres instrucciones de invocación devolución: escribir tres instrucciones de devolución bloque secuencial: escribir tres bloques secuenciales de instrucciones instrucción condicional: escribir tres instrucciones condicionales instrucción iterativa: escribir tres instrucciones iterativas 7 1.6. Reglas sintácticas para la escritura de algunos tipos de datos En este problema se va a pedir la escritura de reglas sintácticas que determinen cómo han de ser presentados determinados datos. Un número dni. El número de un DNI (documento nacional de identidad) puede ser, en principio, cualquier número natural. Un letra dni. La letra de un DNI ha de ser una letra mayúscula del alfabeto inglés. Un dni. Un dato de tipo dni se define como una secuencia de un número dni seguido de una letra dni. Un dı́a, un mes y un año se van a representar, cada uno de ellos, mediante un número natural. Una fecha se representa por una secuencia de tres datos, el primero representa el dı́a, el segundo el mes y el tercero el año de la fecha. Una hora, un minuto y un segundo se van a representar, cada uno de ellos, mediante un número natural. Un tiempo es un dato que corresponde a uno de los 84.400 segundos de un dı́a. Se va a representar mediante una secuencia de tres datos, el primero define la hora, el segundo el minuto y el tercero el segundo que determinan un tiempo comprendido entre las 00:00:00 horas y las 23:59:59 horas del dı́a. Un dato del tipo sexo hombre ha de venir representado por un literal booleano, por el literal cierto (si se trata de un hombre) o por el literal falso (si se trata de una mujer). Un dato del tipo estado civil soltero ha de venir representado por un literal booleano, por el literal cierto (si se trata de una persona soltera) o por el literal falso (si se trata de una persona casada). Un nombrePropio es una secuencia de caracteres que comienza por una mayúscula pudiendo, en su caso, estar seguida por una secuencia de minúsculas. Un nombre persona se representa mediante un único nombre propio. Un apellido persona se representa mediante un único nombre propio. Un ciudadano se representa mediante una secuencia integrada por los siguientes datos. Un dato dni, seguido por un dato fecha, que representa su fecha de nacimiento, al que siguen, en este oreden, un dato sexo hombre, un dato estado civil soltero y un dato nombre persona. Concluye la secuencia por uno o dos datos apellido persona. A partir de las definiciones anteriores se deben escribir reglas sintácticas para cada uno de los tipos de datos definidos previamente. En la definición de cualquiera de las reglas sintácticas se puede hacer uso de otras reglas sintácticas definidas previamente en este documento. En cualquier momento se pueden definir reglas sintácticas complementarias a las que se enuncian a continuación para facilitar la escritura de éstas. 8 <número_dni> ::= ... <letra_dni> ::= ... <dni> ::= ... <dia> ::= <mes> ::= <a~ no> ::= ... ... ... <fecha> ::= ... <hora> ::= ... <minuto> ::= ... <segundo> ::= ... <tiempo> ::= ... <sexo_hombre> ::= ... <estado_civil_soltero> ::= ... <nombrePropio> ::= ... <nombre_persona> ::= ... <apellido_persona> ::= ... <ciudadano> ::= ... 9 Capı́tulo 2 Escritura de expresiones aritméticas y lógicas En este capı́tulo se propone una colección de ejercicios para el ejercicio en la escritura de expresiones aritméticas, tanto aquellas cuyos resultados son números enteros como si son números reales, y de expresiones lógicas. 2.1. Escritura de expresiones aritméticas 2.1.1. Escritura de expresiones aritméticas cuyo resultado es un número entero Para escribir las siguientes expresiones se dispone únicamente del siguiente conjunto de operadores aritméticos: + (suma de enteros), - (resta de enteros), * (producto de enteros), / (cociente de la división entera), % (resto de la división entera). Escribir una expresión que determine el número de enteros comprendidos entre los enteros x e y, siendo x ≤ y. Escribir una expresión que determine la cifra menos significativa del número natural n, es decir, la cifra de las unidades cuando n se escribe en base 10. Escribir una expresión que determine la cifra de las decenas de n, cuando n se escribe en base 10. Escribir una expresión que determine la cifra de las centenas de n, cuando n se escribe en base 10. Escribir una expresión que determine el número de baldosas cuadradas de lado 25 cm. necesarias para cubrir una superficie rectangular de dimensiones a y b, donde los valores de a y b son medidas enteras expresadas en metros. Escribir una expresión que determine cuántos cubos de arista 5 cm pueden almacenarse en una caja con forma de ortoedro (paralelepı́pedo ortogonal) cuyas dimensiones son x, y, z, todas ellas enteros múltiplos de 10 cm. Escribir una expresión que determine cuántas bolas esféricas de radio 1 cm pueden almacenarse en una caja con forma de ortoedro (paralelepı́pedo ortogonal) cuyas dimensiones son a, b, c, todas ellas enteros múltiplos de 10 cm. 10 Escribir una expresión que determine el número de semanas completas hay en d dı́as. Se dispone de n bolsas de caramelos, cada una de las cuales contiene m caramelos. Se han de repartir equitativamente todos los caramelos entre los p niños asistentes a una fiesta. Escribir una primera expresión que determine el número de caramelos que recibirá cada niño y escribir una segundo expresión que determine el número de caramelos que no habrán podido ser repartidos para no generar agravios. Una fecha la podemos representar mediante un entero de ocho dı́gitos de la forma aaaammdd, donde aaaa denota el año, mm el mes y dd el dı́a. Ejemplos: 20160101 (primer dı́a del año 2016), 20161231 (últmo dı́a del año 2016) y 14921012 (fecha de la llegada de Cristóbal Colón a América). Dada una fecha descrita del modo anterior por el valor entero f, escribir tres expresiones que determinen el año, el mes y el dı́a que corresponden a la fecha f. Una instante del dı́a lo podemos representar mediante un entero de seis dı́gitos de la forma hhmmss, donde hh denota la hora, mm el minuto y ss el segundo. Ejemplos: 0 (medianoche), 310 (las 3 y 10 de la madrugada), 605 (las 6 y 5 de la madrugada), 120000 (mediodı́a), 183000 (las seis y media de la tarde)y 235959 (un segundo antes de la medianoche). Dado un instante del dı́a descrito del modo anterior por el valor entero momento, escribir tres expresiones que determinen la hora, el minuto y el segundo que corresponden al instante del dı́a momento. Una instante del dı́a también lo podemos representar mediante los segundos transcurridos desde el comienzo del dı́a. Ejemplos: 0 (medianoche), 3600 (la una de la madrugada, es decir, las 00:00:00), 3663 (la 01:01:03), 43200 (mediodı́a, es decir, las 12:00:00), 86399 (un segundo antes de la medianoche). Dado un instante del dı́a descrito del modo anterior por un valor entero segs, escribir tres expresiones que determinen la hora, el minuto y el segundo que corresponden al instante del dı́a segs. Escribir una expresión que determine el valor de la suma de los enteros comprendidos en el intervalo [x,y], siendo x ≤ y. 2.1.2. Escritura de expresiones aritméticas cuyo resultado es un número real Para escribir las expresiones cuyo resultado es un número real se dispone de los siguientes operadores: De los operadores aritméticos enumerados en el apartado anterior para trabajar con datos numéricos enteros. De los siguientes operadores aritméticos: + (suma de reales), - (resta de reales), * (producto de reales), / (división de reales). √ La funcion sqrt(x) que proporciona como resultado x y las funciones sin(x), cos(x) y tan(x) que devuelven los valores de las funciones trigonométricas sen x, cos x y tg x, con el ángulo x expresado en radianes. Se pide escribir las expresiones que se proponen a continuación. Escribir una expresión que determine el área de un rectángulo cuyos lados miden x e y y una segunda expresión que determine la longitud de su diagonal. 11 Escribir una expresión que determine la distancia entre dos puntos cuyas coordenadas cartesianas son (a,b) y (c,d), respectivamente. Dada un circunferencia de radio r, se pide escribir una expresión para calcular su longitud y otra expresión que calcule el área del cı́culo que determina. Dado un polı́gono regular con n lados de longitud lado, se pide escribir una expresión para calcular su área y otra expresión para calcular el valor, en grados sexagesimales, de los ángulos determinados por dos lados consecutivos. Dado un exaedro regular o cubo de arista a, escribir una primera expresión que calcule el área total de sus caras, una segunda expresión que calcule su volumen y una tercera expresión que calcule la longitud de su diagonal. 2.2. Escritura de expresiones lógicas Una expresión lógica es aquella cuya evaluación proporciona como resultado es un valor booleano, es decir, cierto o falso. Para escribir las expresiones lógicas vamos a disponer de los siguientes operadores: Todos los operadores y funciones descritos en los apartados anteriores para la escritura de expresiones aritmética cuyo resultado es un número entero o un número real. Seis operadores de relación: ==, !=, <, <=, > y >=. Tres operadores lógicos: AND (conjunción lógica), OR (negación lógica y NOT (negación lógica). Se pide escribir las expresiones lógicas que se proponen a continuación. Escribir una expresión lógica cuyo valor sea cierto si y sólo si el valor de x es mayor o igual que el valor de y. Escribir una expresión lógica cuyo valor sea cierto si y sólo si los valores de a y de b son diferentes. Escribir una expresión lógica cuyo valor sea cierto si y sólo si el valor de x está comprendido entre los valores de a y de b, es decir, pertenece al intervalo [a,b]. Escribir una expresión lógica cuyo valor sea cierto si y sólo si el valor de x no está comprendido entre los valores de a y de b, es decir, está fuera del intervalo [a,b]. Escribir una expresión lógica cuyo valor sea cierto si y sólo si los valores de a, de b y de c son todos ellos diferentes. Escribir una expresión lógica cuyo valor sea cierto si y sólo si el valor de a el menor de los tres valores a, b y c. Escribir una expresión lógica cuyo valor sea cierto si y sólo si el valor de x es igual que el menor de los tres valores a, b y c. Escribir una expresión lógica cuyo valor sea cierto si y sólo si los valor de a, b, c y d, dichos en este orden, están ordenados de menor a mayor valor. 12 Escribir una expresión lógica cuyo valor sea cierto si y sólo si el valor el entero n no tiene ningún divisor de una cifra, si se exceptúa la unidad. Escribir una expresión lógica cuyo valor sea cierto si y sólo si el valor el entero n tiene algún divisor de una cifra que sea diferente de la unidad. Escribir una expresión lógica cuyo valor sea cierto si y sólo si el punto de coordenadas cartesianas (a,b) está situado en la circunferencia o dentro de un cı́culo con centro en el origen y radio r. Escribir una expresión lógica cuyo valor sea cierto si y sólo si el punto de coordenadas cartesianas (a,b) está situado fuera de un cı́culo con centro en el origen y radio r. Escribir una expresión lógica cuyo valor sea cierto si y sólo si el punto de coordenadas cartesianas (a,b) está situado en el perı́metro o dentro de un cuadrado con centro en el origen y lado h. Escribir una expresión lógica cuyo valor sea cierto si y sólo si el punto de coordenadas cartesianas (a,b) está situado fuera de un cuadrado con centro en el origen y lado h. 13 Capı́tulo 3 Trabajo con datos enteros 3.1. Diseño de funciones para gestionar fechas del calendario Se pide desarrollar un módulo de biblioteca denominado calendario que ofrezca al resto de módulos las funciones que se especifican a continuación. El desarrollo de este módulo requiere escribir sus ficheros de interfaz y de implementación. /∗ ∗ Fichero calendario.h de interfaz del módulo calendario ∗/ /∗ ∗ Pre: anyo >= 1600 ∗ Post: Devuelve [true] si y solo si [anyo] es un año bisieto ∗/ bool esBisiesto (int anyo); /∗ ∗ Pre: anyo >= 1600 ∗ Post: Devuelve el número de dı́as del año [anyo] ∗/ int diasDelAnyo (int anyo); /∗ ∗ Pre: mes >= 1 y mes <= 12 y anyo >= 1600 ∗ Post: Devuelve el número de dı́as del mes [mes] del año [anyo] ∗/ int diasDelMes (int mes, int anyo); /∗ ∗ Pre: fecha escrito en base 10 tiene la forma aaaammdd donde los dı́gitos ∗ aaaa representan el año, los dı́gitos mm el mes y los digitos dd el ∗ dı́a de una fecha ∗ Post: Devuelve el valor del dı́a correspondiente a la fecha del calendario ∗ representada por el entero [fecha] ∗/ int dia (int fecha ); /∗ ∗ Pre: fecha escrito en base 10 tiene la forma aaaammdd donde los dı́gitos ∗ aaaa representan el año, los dı́gitos mm el mes y los digitos dd el 14 ∗ dı́a de una fecha ∗ Post: Devuelve el valor del mes correspondiente a la fecha del calendario ∗ representada por el entero [fecha] ∗/ int mes (int fecha ); /∗ ∗ Pre: fecha escrito en base 10 tiene la forma aaaammdd donde los dı́gitos ∗ aaaa representan el año, los dı́gitos mm el mes y los digitos dd el ∗ dı́a de una fecha ∗ Post: Devuelve el valor del año correspondiente a la fecha del calendario ∗ representada por el entero [fecha] ∗/ int anyo (int fecha ); /∗ ∗ Pre: El trı́o de datos (dia,mes,anyo) definen una fecha válida del calendario, ∗ la fecha dia/mes/anyo ∗ Post: Devuelve un entero que, al ser escrito en base 10, tiene la forma aaaammdd ∗ que representa la fecha dia/mes/anyo donde los dı́gitos aaaa representan el , ∗ año los dı́gitos mm el mes y los digitos dd el dı́a ∗/ int fecha (int dia, int mes, int anyo); /∗ ∗ Pre: f escrito en base 10 tiene la forma aaaammdd donde los dı́gitos aaaa ∗ representan el año, los dı́gitos mm el mes y los digitos dd el dı́a de una ∗ fecha. La fecha [ f ] es igual o posterior al 1/1/1600 ∗ Post: Devuelve el número de dı́a en el año de la fecha [ f ] ∗/ int diaDelAnyo (int f); /∗ ∗ Pre: f escrito en base 10 tiene la forma aaaammdd donde los dı́gitos aaaa ∗ representan el año, los dı́gitos mm el mes y los digitos dd el dı́a de una ∗ fecha. La fecha [ f ] es igual o posterior al 1/1/1600 ∗ Post: Devuelve el número de dı́a de la semana de la fecha [f ], con la convención de ∗ que el lunes es el primer dı́a de la semana y el domingo el séptimo y último. ∗ Devolverá, por lo tanto, un valor entre el 1 (lunes) y el 7 (domingo). ∗/ int diaDeLaSemana (int f); /∗ ∗ Pre: d >= 1 y d <= 7 ∗ Post: Escribe por pantalla , en castellano , el nombre del dı́a de la semana número [d]. ∗ Si d=1 escribe ”lunes”, si d=2 escribe ”martes”, etc. ∗/ void escribeDia (int d); /∗ ∗ Pre: m>=1 y m<=12 ∗ Post: Escribe por pantalla , en castellano , el nombre del mes número [m]. ∗ Si m=1 escribe ”enero”, si m=2 escribe ”febrero”, etc. ∗/ void escribeMes (int m); /∗ ∗ Pre: mes >= 1, mes <= 12 y año >= 1600 ∗ Post: Presenta por pantalla el calendario del mes [mes] del año [año] con 15 ∗ un formato similar el mostrado en el siguiente ejemplo: ∗ ∗ septiembre 2015 ∗ 1 2 3 4 5 6 ∗ 7 8 9 10 11 12 13 ∗ 14 15 16 17 18 19 20 ∗ 21 22 23 24 25 26 27 ∗ 28 29 30 ∗/ void calendario (int mes, int anyo); 16 Capı́tulo 4 Trabajo con datos reales En cada uno de los problemas que se plantean a continuación se pide el desarrollo de un módulo de biblioteca. Por cada módulo, habrá que programar sus ficheros de interfaz y de implementación. En cada uno de los problemas conviene desarrollar también uno o más programas de prueba para verificar el correcto comportamiento de las funciones definidas en el módulo de biblioteca pedido. Cada alumno tiene libertad para definir sus programas de prueba. 4.1. Cálculo de magnitudes geométricas de polı́gonos regulares Se pide desarrollar un módulo de biblioteca denominado poligonos que ofrezca al resto de módulos las funciones que se especifican a continuación. /∗ ∗ Fichero de interfaz poligonos .h ∗/ /∗ ∗ Pre: n>=3 y lado>=0.0 ∗ Post: devuelve la longitud del área encerrada por un polı́gono regular de [n] lados ∗ de longitud [lado] ∗/ double area (int n, double lado); /∗ ∗ Pre: n>=3 y lado>=0.0 ∗ Post: devuelve la longitud del perı́metro de un polı́gono regular de [n] lados ∗ de longitud [lado] ∗/ double perimetro (int n, double lado); /∗∗ ∗ Pre: n>=3 y lado>=0.0 ∗ Post: devuelve la longitud del apotema de un polı́gono regular de [n] lados ∗ de longitud [lado] ∗/ double apotema (int n, double lado); 17 /∗ ∗ Pre: n>=3 y lado>=0.0 ∗ Post: devuelve la longitud del radio de la circunferencia circunscrita de un polı́gono ∗ regular de [n] lados de longitud [lado] ∗/ double radio (int n, double lado): /∗ ∗ Pre: n>=3 y lado>=0.0 ∗ Post: devuelve el valor , en grados sexagesimales, de los ángulos interiores de un polı́gono ∗ regular de [n] lados de longitud [lado] ∗/ double anguloInterior (int n, double lado); 4.2. Caracterización de la caida libre de un sólido rı́gido Se pide desarrollar el módulo de biblioteca caida que ofrecerá al resto de módulos dos funciones que permiten calcular la duración del movimiento en caida libre de un cuerpo y la velocidad máxima alcanzada al llegar al suelo. Asumimos que la caida libre se produce al soltar el cuerpo desde una altura h y que el rozamiento del aire es despreciable. El cuerpo sufre una aceleración por acción de la gravedad, g, igual a 9,81 sm2 , hasta llegar al suelo con una velocidad máxima v después de un tiempo t. Las siguientes relaciones son fácilmente deducibles (en caso de duda se puede consultar algún libro de fı́sica elemental o acudir a páginas especializadas de internet): v =g×t h = 12 g × t2 /∗ ∗ Fichero de interfaz caida.h ∗/ /∗ ∗ Pre: [h] es la altura , en metros, desde la que inicia la caida libre y sin rozamiento ∗ un objeto ∗ Post: Devuelve el tiempo, en segundos, que tarda el objeto en llegar al suelo ∗/ double tiempo (double h); /∗ ∗ Pre: [h] es la altura , en metros, desde la que inicia la caida libre y sin rozamiento ∗ un objeto ∗ Post: Devuelve la velocidad , en metros/segundo, a la que impacta el objeto en el suelo ∗/ double velocidad (double h); 4.3. Caracterización de un tiro parabólico La trayectoria que describe una pelota de tenis al ser lanzada sin efecto es una parábola. Las trayectorias descritas por un proyectil disparado por un arma de fuego o por una flecha lanzada 18 desde un arco también son parábolas. Cualquiera de nosotros puede lanzar una piedra con un determinado ángulo de inclinación y ella decribirá una parábola. El lanzamiento de cualquiera de estos objetos se denomina tiro parabólico o tiro oblicuo. Imaginemos que estamos situados sobre una superficie horizontal y que lanzamos un objeto con una velocidad v, expresada en m/s, en una direción que forma un ángulo α con relación a la superficie horizontal sobre la que estamos ubicados. El objeto lanzado irá elevándose y alejándose de nosotros hasta alcanzar una altura máxima. A partir de ese momento continuará alejándose de nosotros e irá perdiendo altura hasta caer sobre la superficie horizontal. Si denominamos y al valor de la altura alcanzada en cada instante t por el objeto lanzado y denominamos x al valor de su distancia en cada instante, medida en horizontal, respecto del punto de lanzamiento, podemos escribir las relaciones que describen la trayectoria parabólica del objeto en función del tiempo t: x = v × cos α × t y = v × sen α × t − 12 g × t2 En este problema se pide diseñar un módulo de biblioteca, denominado tiro, que ofertará cuatro funciones que permiten calcular cuatro datos referidos a la trayectoria descrita por un objeto lanzado mediante tiro parabólico: Función alturaMaxima(v, angulo) que devuelve la máxima altura alcanzada por el objeto. Función tiempoMaximo(v, angulo) que devuelve el tiempo que tarda el objeto en alcanzar esa altura máxima, medido desde el instante en que fue lanzado. Función distanciaCaida(v, angulo) que devuelve el alejamiento horizontal del objeto respecto del punto de lanzamiento, que corresponde a la distancia entre el punto de lanzamiento y el punto de caida. Función tiempoCaida(v, angulo) que devuelve el tiempo que ha tardado el objeto en caer, medido desde el instante en que fue lanzado. /∗ ∗ Fichero de interfaz tiro .h ∗/ /∗ ∗ Pre: [v] es la velocidad , expresada en m/s, a la que es lanzado un objeto y [angulo] es ∗ el ángulo, expresado en grados sexagesimales, que forma la dirección de lanzamiento ∗ del objeto con la superficie horizontal . Debe satisfacerse que angulo>=0o y que ∗ angulo<=90o ∗ Post: Devuelve la altura máxima, en metros, que llega a alcanzar el objeto en su trayectoria ∗ parabólica sin rozamiento, medida respecto de la superficie horizontal ∗/ double alturaMaxima (double v, double angulo); /∗ ∗ Pre: [v] es la velocidad , expresada en m/s, a la que es lanzado un objeto y [angulo] es ∗ el ángulo, expresado en grados sexagesimales, que forma la dirección de lanzamiento ∗ del objeto con la superficie horizontal . Debe satisfacerse que angulo>=0o y que ∗ angulo<=90o 19 ∗ Post: Devuelve el tiempo, en segundos, que tarda el objeto en alcanzar la máxima altura ∗ de su trayectoria parabólica sin rozamiento respecto de la superficie horizontal . ∗/ double tiempoMaximo (double v, double angulo); /∗ ∗ Pre: [v] es la velocidad , expresada en m/s, a la que es lanzado un objeto y [angulo] es ∗ el ángulo, expresado en grados sexagesimales, que forma la dirección de lanzamiento ∗ del objeto con la superficie horizontal . Debe satisfacerse que angulo>=0o y que ∗ angulo<=90o ∗ Post: Devuelve la distancia , en metros, que hay entre el punto de lanzamiento y el punto ∗ de caida sobre la misma la superficie horizontal , tras describir una trayectoria ∗ parabólica sin rozamiento ∗/ double distanciaCaida (double v, double angulo); /∗ ∗ Pre: [v] es la velocidad , expresada en m/s, a la que es lanzado un objeto y [angulo] es ∗ el ángulo, expresado en grados sexagesimales, que forma la dirección de lanzamiento ∗ del objeto con la superficie horizontal . Debe satisfacerse que angulo>=0o y que ∗ angulo<=90o ∗ Post: Devuelve el tiempo, en segundos, que tarda el objeto en caer de nuevo sobre la ∗ superficie horizontal , tras describir una trayectoria parabólica sin rozamiento ∗/ double tiempoCaida (double v, double angulo); } En caso necesario, se recomienda consultar algún libro de fı́sica elemental o acudir a páginas especializadas de internet para recordar las ecuaciones del tiro parabólico y las fórmulas que de ellas se deducen. 4.4. Amortización de un préstamo En este problema se debe diseñar un módulo de biblioteca, denominado prestamo, que ofrezca a otros módulos las funciones tae, nominal y tablaAmortizacion tal como se especifican a continuación. /∗ ∗ Fichero de interfaz prestamo.h ∗/ /∗ ∗ Pre: [r] es una tasa anual nominal de interés de un préstamo ∗ Post: devuelve la tasa anual equivalente (TAE) del mismo préstamo ∗/ double tae (double r); /∗ ∗ Pre: [tae] es la tasa anual equivalente (TAE) de un préstamo ∗ Post: devuelve la tasa anual nominal del mismo préstamo ∗/ double nominal (double tae); /∗ ∗ Pre: capital >=0.0, numMeses>0, r>0.0 ∗ Post: Presenta por pantalla la tabla de amortización de un préstamo de [capital] 20 ∗ euros a amortizar en [numMeses] meses con una tasa anual de interés nominal ∗ del [r] por ciento ∗/ void tablaAmortizacion (double capital, int numMeses, double r); El modo en que la función tablaAmortizacion debe presentar los datos de una tabla de amortización se ilustran a continuación mediante el siguiente ejemplo de aplicación. Una invocación tablaAmortizacion(100000.0, 18, 4.8) presenta por pantalla la tabla de amortización de un préstamo de 100000 euros a un interés nominal del 4.8% con un periodo de amortización de 18 meses durante los cuales se paga una cuota constante. A continuación se muestran los resultados que dicha invocación presenta por pantalla. Comienzan con los datos del capital prestado, el periodo de amortización, la tasa de interés nominal y su TAE equivalente y la cuota mensual constante a pagar. A continuación presenta la tabla de amotozación propiamento dicha con cinco columnas: número de mes, cantidad pagada ese mes, parte de la cantidad anterior dedicada a amortizar capital, parte de la cantidad anterior dedicada al pago de intereses y capital pendiente de amortizar. La última lı́nea de la tabla presenta los totales de las cantidades pagadas, amortizadas y abonadas como interés. Capital prestado: 100000,00 euros Periodo de amortización: 18 meses Interés anual nominal: 4,80 (TAE: 4,91) Cuota constante: 5769,05 euros/mes MES 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 PAGADO 0,00 5769,05 5769,05 5769,05 5769,05 5769,05 5769,05 5769,05 5769,05 5769,05 5769,05 5769,05 5769,05 5769,05 5769,05 5769,05 5769,05 5769,05 5769,05 TOTAL 103842,98 AMORTIZADO 0,00 5369,05 5390,53 5412,09 5433,74 5455,48 5477,30 5499,21 5521,20 5543,29 5565,46 5587,72 5610,07 5632,51 5655,04 5677,67 5700,38 5723,18 5746,07 100000,00 INTERESES 0,00 400,00 378,52 356,96 335,31 313,58 291,76 269,85 247,85 225,77 203,59 181,33 158,98 136,54 114,01 91,39 68,68 45,88 22,98 PENDIENTE 100000,00 94630,95 89240,42 83828,32 78394,58 72939,11 67461,81 61962,60 56441,40 50898,11 45332,65 39744,92 34134,85 28502,33 22847,29 17169,62 11469,25 5746,07 0,00 3842,98 0,00 En caso necesario, se recomienda consultar algún libro introductorio de Economı́a o acudir a páginas especializadas de internet para documentarse sobre cómo calcular el TAE de un préstamo, los intereses mensuales a satisfacer o la cuota mensual constante a pagar. 21