# PR 2 [Volver a la página principal de "Fundamentos de la Programación"](../README.md) **Índice** - [PR 2](#pr-2) - [12. Modularidad](#12-modularidad) - [12.1 Aproximación intuitiva](#121-aproximación-intuitiva) - [12.1.1. Ejemplo - Cálculo de combinaciones](#1211-ejemplo---cálculo-de-combinaciones) - [12.2 Funciones](#122-funciones) - [12.2.1. Sintaxis para la declaración de una función](#1221-sintaxis-para-la-declaración-de-una-función) - [12.3. Acciones](#123-acciones) - [12.3.1. Sintaxis para la declaración de una función](#1231-sintaxis-para-la-declaración-de-una-función) - [12.4. Cómo utilizar (llamar) a una función y/o acción](#124-cómo-utilizar-llamar-a-una-función-yo-acción) - [12.4.1. Llamada a una función](#1241-llamada-a-una-función) - [12.4.2. Llamada a una acción](#1242-llamada-a-una-acción) - [12.5. Clases de parámetros de una acción](#125-clases-de-parámetros-de-una-acción) - [12.5.1. Parámetros de entrada](#1251-parámetros-de-entrada) - [12.5.2. Parámetros de salida](#1252-parámetros-de-salida) - [12.5.3. Parámetros de entrada/salida](#1253-parámetros-de-entradasalida) - [12.6. Funciones contra acciones](#126-funciones-contra-acciones) - [12.7. Acciones y funciones predefinidas](#127-acciones-y-funciones-predefinidas) - [12.8. Modularización](#128-modularización) - [12.9 Ejercicios](#129-ejercicios) - [12.10 Soluciones en lenguaje algorítmico](#1210-soluciones-en-lenguaje-algorítmico) ## 12. Modularidad La modularidad es una técnica de programación que consiste en dividir un programa en partes más pequeñas y manejables. Cada parte se denomina módulo y puede ser un subprograma, una función, una acción, un procedimiento, una rutina, un método, etc. La modularidad permite dividir un problema complejo en problemas más simples y fáciles de resolver. Además, facilita la reutilización de código, la depuración y el mantenimiento de los programas. ### 12.1 Aproximación intuitiva Un ejemplo con una comida: ``` algorithm almuerzo var primerPlato, salsa, segundoPlato, postres: tPlato; end var primerPlato:= encargarPaella(marisco, 5); segundoPlato:= encargarPescado(bacalao, ajoaceite, 5); postres:= encargarPostres(pastel, chocolate, velas, 5); end algorithm ``` Podemos ver cómo nuestro algoritmo, a base de solicitar a expertos que hagan el trabajo, se convierte en un algoritmo simple y fácil de entender. Lo único que hemos tenido que hacer son peticiones en las que hemos añadido valores, a los que llamamos **parámetros**, que indican exactamente cómo queremos cada plato. Los lenguajes de programación permiten trabajar de una forma similar a como lo hemos hecho en el menú. Es decir, se pueden utilizar subalgortimos, o se pueden definir otros nuevos, que quedan aparte del algoritmo principal y que permiten dividir un algoritmo complicado en subalgoritmos más simples. Además, como veremos en los siguientes apartados, otra de las ventajas que proporcionan es el hecho de que estos subalgoritmos se pueden reutilizar evitando la reescritura de código. Estos subalgoritmos reciben el nombre de **acciones** y **funciones** y es como si empaquetásemos un conjunto de instrucciones que resuelven un problema y no nos tenemos que preocupar de lo que hay dentro. #### 12.1.1. Ejemplo - Cálculo de combinaciones Supongamos que tenemos que diseñar un algoritmo que permita saber cuántas combinaciones de colores se pueden hacer si disponemos de `n` telas, cada una de un color diferente. Concretamente se quiere disponer de un algoritmo genérico que dados `n` colores calcule cuantas combinaciones se pueden hacer utilizando cada vez `m` colores, donde `m` y `n` son enteros y `m ≤ n`. Para diseñar el algoritmo deberemos leer los valores de n y m y haberlo indicado en la fórmula. Quedaría: ```c algorithm combinations var {definimos las variables, dos enteros que hay que leer y una donde almacenar el resultado} totalNumColors, colorsToCombine: integer ; result: integer; end var {leemos los dos números} totalNumColors:= readInteger(); colorsToCombine:= readInteger(); {Hacemos un esbozo del cálculo, suponiendo que disponemos de una manera de calcular el factorial de un número } result := totalNumColors! div (colorsToCombine! * (totalNumColors-colorsToCombine)!) ; writeInteger(result); end algorithm #include int main() { int totalNumColors; int colorsToCombine; int result; result = totalNumColors! / (colorsToCombine! * (totalNumColors-colorsToCombine)!) ; printf ("%d ", result); return 0; } ``` Ahora bien, para calcular el factorial de las posible combinaciones se necesita hacer una iteración para ir calculando el producto de todos los enteros, además de la necesidad de variables donde guardar los cálculos parciales:: ```c var factorial: integer; i: integer; n: integer; end var n:= readInteger(); factorial:= 1; i:=1; while i ≤ n do factorial:=factorial*i; i:=i+1; end while #include int main() { int factorial; int i; int n; scanf("%d", &n); factorial=1; i=1; while(i <= n) { factorial = factorial*i; i++; } return 0; } ``` Si incorporamos este código en el algoritmo anterior, el código se complica y se hace menos legible. Deberíamos repetir el código cada vez que necesitaramos el cálculo. La solución es encapsular este código en una **acción** o **función** que se encargue de calcular el factorial de un número cada vez que se necesite con una llamada que pase el parámetro. De esta forma, el algoritmo principal quedaría más limpio y fácil de entender. ### 12.2 Funciones Una función es un conjunto independiente de instrucciones que resuelven una tarea concreta, que devuelve un valor y que puede ser referenciada (invocada o llamada) desde otro punto del programa. #### 12.2.1. Sintaxis para la declaración de una función Para definir una función necesitaremos los siguientes elementos: - **Nombre** para poder identificarla. - Una serie de valores sobre los que se quieran hacer los cálculos, que se denominan **parámetros formales** de la función. Es necesario indicar el nombre y el tipo de dato de cada uno de los parámetros. Actúan como variables locales a la función. - Las instrucciones de la función, es decir, el **cuerpo de la función**. - El valor resultante de la función al que se debe indicar el tipo de dato que se va a devolver. Este valor se devuelve mediante la instrucción `return`. Sintaxis: ```c function name(param1: type1 , param2: type2, ..., paramn: typen): returnType ... ... return expression; end function returnType name(type1 param1, type2 param2, ..., typen paramn) { ... ... /* returnValue es el valor que calcula la función */ return returnValue; } ``` La **cabecera** es la parte que describe cómo debe llamarse a una función. Indica su nombre, los parámetros que espera y el tipo que retorna. La estructura de la cabecera es la siguiente: ```c function name(param1: type1 , param2: type2, ..., paramn: typen): returntype; returnType name(type1 param1, type2 param2, ..., typen param); ``` Volviendo a nuestro ejemplo del factorial, la función sería: ```c function factorial (number: integer): integer var fact: integer; i: integer; end var fact:= 1; i:=1; while i ≤ number do fact:= fact*i; i:= i+1; end while return fact; end function #include int factorial(int number) { int fact; int i; fact=1; i=1; while(i <= number) { fact = fact*i; i++; } return fact; } ``` Aquí vemos: - El nombre factorial para identificar la función. - Un único parámetro, en este caso un entero, para identificar el número sobre el que queremos hacer el cálculo del factorial. - El tipo de retorno, que también será entero. - El cuerpo de la función, que hace los cálculos. Recordemos que las variables son locales a la función, es decir, que no se pueden utilizar fuera de la función. ### 12.3. Acciones A veces interesa un subalgoritmo que realice una serie de instrucciones sin devolver un valor. En estos casos, el lenguaje algorítmico generaliza el concepto de función y define la **acción**. Una acción es un conjunto de instrucciones que resuelven una tarea concreta y que puede ser referenciada (invocada o llamada). Se diferencia de una función porque: - No devuelve ningún valor. - Cuando modifica un parámetro formal, puede estar también modificando el parámetro real. - Se debe indicar delante del nombre del parámetro cómo se pasa. Utilizamos las palabras clave `in`, `out` o `inout`. #### 12.3.1. Sintaxis para la declaración de una función Para definir una acción necesitaremos los siguientes elementos: - **Nombre** para poder identificarla. - Una serie de valores sobre los que se quieran hacer los cálculos, que se denominan **parámetros formales** de la acción. Es necesario indicar el nombre y el tipo de dato de cada uno de los parámetros. Actúan como variables locales a la acción. - Las instrucciones de la acción, es decir, el **cuerpo de la acción**. Sintaxis: ```c action name(class1 param1: type1 , class2 param2: type2, ..., classn paramn: typen) ... ... end action void name(type1 param1, type2 param2, ..., typen paramn) { ... ... } ``` ### 12.4. Cómo utilizar (llamar) a una función y/o acción Una vez definida la acción o función esta se puede utilizar desde el algoritmo principal o desde otra función o desde otra acción. Para llamar a una función o acción se utiliza el nombre de la función o acción seguido de los parámetros que se le pasan entre paréntesis. Los **parámetros reales** pueden ser variables, constantes o expresiones, que deben coincidir en número, tipo y orden con los parámetros formales. #### 12.4.1. Llamada a una función Ejemplo: ```c {Si suponemos que tenemos la siguiente cabecera} function name(param1: integer , param2: real, param3: char): integer; {y suponemos que tenemos la declaración de las siguientes variables} var a: integer; b: real; c: char; result: integer; end var {La manera de llamar a la función sería:} result := name(a, b, c); {Las variables a, b y c son los parámetros actuales de la función} //Si suponemos que tenemos la siguiente cabecera: int name(int param1, float param2, char param3); //Y suponemos que tenemos la declaración de las siguientes variables: int a; float b; char c; int result; //La manera de llamar a la función en C sería: result = name(a, b, c); //Las variables a, b y c son los parámetros actuales de la función ``` En el caso del factorial, la cabecera era: ```c function factorial (number: integer): integer; ``` Las posibles maneras de llamar a la función serían: ```c n:= factorial(5); /* utilizando una constante como parámetro actual*/ n:= factorial(p) /* utilizando una variable como parámetro actual */ n:= factorial(m+2) /* utilizando una expresión como parámetro actual */ ``` Ahora ya podemos ver el algoritmo completo del factorial: ```c function factorial (number: integer): integer var fact: integer; i: integer; end var fact:= 1; i:=1; while i ≤ number do fact:=fact*i; i:=i+1; end while return fact; end function algorithm combinations var {definimos las variables, dos enteros que hay que leer y una donde almacenar el resultado } totalNumColors, colorsToCombine: integer ; result: integer; end var {leemos los números} totalNumColors:= readInteger(); colorsToCombine:= readInteger(); result := factorial(totalNumColors) div ( factorial(colorsToCombine) * factorial(totalNumColors-colorsToCombine)); writeInteger(result); end algorithm #include int factorial(int number) { int fact; int i; fact = 1; i = 1; while(i <= number) { fact = fact*i; i++; } return fact; } int main() { int totalNumColors; int colorsToCombine; int result; scanf("%d", &totalNumColors); scanf("%d", &colorsToCombine); result = factorial(totalNumColors) / ( factorial(colorsToCombine) * factorial(totalNumColors-colorsToCombine)); printf ("%d ", result); return 0; } ``` #### 12.4.2. Llamada a una acción Ejemplo: ```c {Si suponemos que tenemos la siguiente cabecera de una acción con todos los parámetros de entrada} action name(in param1: integer , in param2: real, in param3: char); {y suponemos que tenemos la declaración de las siguientes variables} var a: integer; b: real; c: char; end var {La manera de llamar a la acción sería:} name(a, b, c); {Las variables a, b y c son los parámetros actuales de la acción} //Si suponemos que tenemos la siguiente cabecera: void name(int param1, float param2, char param3); //Y suponemos que tenemos la declaración de las siguientes variables: int a; float b; char c; //La manera de llamar a la acción en C sería: name(a, b, c); //Las variables a, b y c son los parámetros actuales de la acción ``` ### 12.5. Clases de parámetros de una acción Los parámetros de una acción pueden ser de tres tipos: - **Parámetro de entrada (in)**. El valor del parámetro solamente será consultado y utilizado dentro de la acción. Esta manera de pasar parámetros es típica de funciones matemáticas y es la única manera que puede usarse en las funciones. - **Parámetro de salida (out)**. Se utiliza para asignar un valor al parámetro. Si el parámetro ya tiene un valor inicial, este valor no se debería utilizar dentro de la acción. Normalmente se pasan los parámetros de esta manera para que sean inicializados por la acción. Puesto que la acción dejará un valor en el parámetro, este debe ser obligatoriamente una variable. - **Parámetro de entrada/salida (inout)**. Se utilizan para actualizar el valor del parámetro. En este caso, el valor inicial del parámetro se puede utilizar y también se puede modificar, devolviendo un nuevo valor a quien ha llamado a la acción. Puesto que la acción dejará un nuevo valor en el parámetro, este debe ser obligatoriamente una variable. #### 12.5.1. Parámetros de entrada Disponemos de una acción que, dados el número de piezas compradas a un mayorista y el precio por pieza, calcula el coste total y lo muestra por el canal estándar, teniendo en cuenta que según el número de piezas, se aplicará un tipo de descuento u otro: ```c const MAX_DISCOUNT: real = 0.15; MIN_DISCOUNT: real = 0.05; LIMIT: integer = 1000; end const action computeCost(in num: integer, in price: real) var val: real; discount: real; end var if num ≥ LIMIT then discount:= MAX_DISCOUNT; else discount:= MIN_DISCOUNT; end if val:= integerToReal(num) * price * (1.0 - discount); writeReal(val); end action algorithm example1 var num: integer; price: real; end var num:= 1005; price:= 10.0; computeCost(num, price); end algorithm #include #define MAX_DISCOUNT 0.15 #define MIN_DISCOUNT 0.05 #define LIMIT 1000 void computeCost(int num, float price) { float val; float discount; if (num >= LIMIT) { discount = MAX_DISCOUNT; } else { discount = MIN_DISCOUNT; } val = (float) (num)*price* (1.0 - discount); printf("%f", val); } int main() { float price; int num; num = 1005; price = 10.0; computeCost(num, price); return 0; } ``` Comentarios: - Aunque los parámetros formales y actuales tengan el mismo nombre, se trata de variables diferentes. - Podemos ver que los parámetros actuales no han cambiado. #### 12.5.2. Parámetros de salida El ejemplo anterior pero con una acción que tiene un parámetro de salida para devolver el coste: ```c const MAX_DISCOUNT: real = 0.15; MIN_DISCOUNT: real = 0.05; LIMIT: integer = 1000; end const action computeCost(in num: integer, in price: real, out val: real) var discount: real; end var if num ≥ LIMIT then discount:= MAX_DISCOUNT; else discount:= MIN_DISCOUNT; end if val:= integerToReal(num) * price * (1.0 - discount); end action algorithm example2 var num: integer; price: real; cost: real; end var num:= 1005; price:= 10.0; computeCost(num, price, cost); writeReal(cost); end algorithm #include #define MAX_DISCOUNT 0.15 #define MIN_DISCOUNT 0.05 #define LIMIT 1000 void computeCost(int num, float price, float *val) { float discount; if (num >= LIMIT) { discount = MAX_DISCOUNT; } else { discount = MIN_DISCOUNT; } *val = (float) (num)*price* (1.0 - discount); } int main() { float price; int num; float cost; num = 1005; price = 10.0; computeCost(num, price, &cost); printf("%f", cost); return 0; } ``` Comentarios: - Al tratarse de una acción, se llama sin asignar el retorno a una variable, ya que las acciones no retornan ningún valor. - La acción tiene un parámetro formal de salida. Esto quiere decir que cada vez que se modifique este parámetro dentro de la acción, automáticamente se modificará con el mismo valor el parámetro actual correspondiente cost. - Podemos ver que en lenguaje C, los parámetros de salida son en realidad **Punteros**. Más adelante se muestra un ejemplo. #### 12.5.3. Parámetros de entrada/salida Supongamos ahora que el coste final es la suma de unos gastos mínimos (coste de entrega, etc.) más el coste de venta. El coste mínimo viene dado por una constante BASIC_COST. ```c const MAX_DISCOUNT: real = 0.15; MIN_DISCOUNT: real = 0.05; LIMIT: integer = 1000; BASIC_COST: real = 100.0; end const action computeCost(in num: integer, in price: real, inout val: real) var discount: real; end var if num ≥ LIMIT then discount:= MAX_DISCOUNT; else discount:= MIN_DISCOUNT; end if val:= val + integerToReal(num) * price * (1.0 - discount); end action algorithm example3 var num: integer; price: real; cost: real; end var num:= 1005; price:= 10.0; cost:= BASIC_COST; computeCost(num, price, cost); writeReal(cost); end algorithm #include #define MAX_DISCOUNT 0.15 #define MIN_DISCOUNT 0.05 #define LIMIT 1000 #define BASIC_COST 100.0 void computeCost(int num, float price, float *val) { float discount; if (num >= LIMIT) { discount = MAX_DISCOUNT; } else { discount = MIN_DISCOUNT; } *val = *val + (float) (num) * price * (1.0 - discount); } int main() { float price; int num; float cost; num = 1005; price = 10.0; cost = BASIC_COST; computeCost(num, price, &cost); printf("%f", cost); return 0; } ``` Comentarios: - La única diferencia con el ejemplo 2 es que el parámetro val ahora es de entrada y salida y su valor se actualiza sumándole el coste de venta. ### 12.6. Funciones contra acciones **Función**: el criterio para usar una función es evaluar si esta puede actuar como una función matemática que, dados unos parámetros, puede retornar un valor concreto que se puede utilizar como un miembro de una expresión. Si es así, claramente debemos escribir una función. **Acción**: si necesitamos actualizar uno de los parámetros o inicializar uno que no lo está, claramente debemos usar una acción. También se utiliza cuando no se retorna ningún valor o cuando se deben devolver más de uno. Muchas veces las acciones tienen algunos parámetros de salida, pero se podría dar el caso de que no tenga ninguno como, por ejemplo, en el caso de que la acción lea la información del canal estándar y saque también los resultados directamente por el canal estándar. ### 12.7. Acciones y funciones predefinidas Tanto en el lenguaje algorítmico como en los de programación, hay algunas acciones y funciones ya definidas por defecto. Entre otras tenemos: - Funciones de conversión de tipo. - Acciones y funciones de entrada y salida de datos. Las funciones de conversión de tipo son esas que transforman una variable de un tipo a otro: ```c function integerToReal(x: integer): real; function realToInteger(x: real): integer; function charToCode(c: char): integer; function codeToChar(x: integer): char; #include int main() { int x; float y; char c; y = (float) x; x = (int) y; x = (int) c; c = (char) x; } ``` Las acciones/funciones de entrada y salida de datos son esas que permiten recibir datos del exterior (teclado, ficheros, etc.) y mostrar datos al exterior: ```c function readInteger(): integer; function readReal(): real; function readChar(): char; function readString(): string; action writeInteger(in x: integer); action writeReal(in x: real); action writeChar(in x: char); action writeString(in x: string); #include int main() { int x; float y; char c; string s; scanf("%d", &x); scanf("%f", &y); scanf("%c", &c); scanf("%s", s); printf("%d ", x); printf("%f ", y); printf("%c ", c); printf("%s ", s); return 0; } ``` ### 12.8. Modularización Para mantener el conjunto de acciones y funciones ordenadas y que se puedan utilizar en diferentes programas de manera fácil, los lenguajes permiten crear **librerías**. Estas librerías constan de dos partes: - Un fichero de texto que inclute las cabeceras de las acciones y funciones que la componen y que en C tienen siempre la extensión `.h`. - El código de las acciones y funciones, que también tendrá un extensión `.c`, pero que solamente tendrá el código de la acciones y/o funciones, sin tener un `main`. Cuando se tendan que emplear desde algún otro programa solamente se incluirán en el programa el fichero de cabeceras.h. La sintaxis: ```c #include "nomLlibreria.h" ``` Concretamente, la librería que incluye las cabeceras de las acciones y funciones de entrada y salida de datos se llama en C `stdio.h`: ```c #include ``` Hay muchos ejemplos de librerías, por ejemplo: - Librerías de funciones matemáticas. `math.h`, `stdlib.h`, etc. - Librerías de funciones y acciones de tratamiento de fechas. `time.h`, `date.h`, etc. - Librerías de funciones de tratamiento de cadenas de caracteres. `string.h`, etc. La posibilidad de crear las librerías facilita la reutilización del código y estandarización de la manera de trabajar. ### 12.9 Ejercicios 1. Diseñad una función que, dado un entero n, calcule la suma de los primeros n números de la serie Fibonacci. [Solución en lenguaje C](./soluciones_c/solucion1/fibonacci.c) 2. Diseñad una acción que, dados un real que representa el saldo de una cuenta corriente y otro real que representa un cargo o imposición, actualice el saldo de la cuenta. [Solución en lenguaje C](./soluciones_c/solucion2/saldo_cuenta.c) 3. Diseñad una función que calcule n (real) elevado a la potencia m (entero). [Solución en lenguaje C](./soluciones_c/solucion3/potencia.c) 4. Diseñad una acción que, dados tres números reales que representan los coeficientes de una ecuación de segundo grado, retorne sus raíces, en caso de que existan. En caso contrario, que inicialice las raíces a 0. Recordad que dada la ecuación A * x2 + B * x + C las raíces se calculan: ``` x1 = (-B + sqrt(B2 - 4 * A * C)) / (2 * A) ``` Si la expresión dentro de la raíz es negativa quiere decir que la ecuación no tiene raíces. Podéis suponer que la función raíz cuadrada está ya definida y su cabecera es: ``` function squareRoot(x: real): real; ``` Declarad las variables necesarias para llamar a la acción del ejercicio anterior e indicad cómo se llamaría. [Solución en lenguaje C](./soluciones_c/solucion4/ecuacion_segundo_grado.c) 5. Para cada apartado siguiente, decidid si es mejor una acción o una función y definid su cabecera (solamente se pide la cabecera, no hay que diseñar ningún algoritmo). - Dadas las dimensiones de una pared (altura y anchura) y el precio de pintura por metro cuadrado, determinad el coste total de pintura necesario para pintar la pared. - Dado el consumo total de agua acumulado desde el mes de enero hasta junio (ambos incluidos), leed por el canal estándar el consumo del resto de meses (desde julio a diciembre, ambos incluidos), y retornadlo acumulado al total del consumo de los 6 primeros meses. - Dados dos números enteros intercambiad los valores de ambas variables siempre que ambas sean diferentes de cero. - Dado un entero retornad la suma de sus divisores. Declarad las variables necesarias para llamar a las acciones del ejercicio anterior e indicad cómo se llamarían. [Solución en lenguaje C](./soluciones_c/solucion5/calculos_varios.c) (He añadido algunos extras para jugar) ### 12.10 Soluciones en lenguaje algorítmico 1. Solución ```alg function fibonacci(n: integer): integer var i, suma, a, b: integer; end var if n < 3 then suma:= 1; else a:= 0; b:= 1; suma:= 0; for i:= 1 to n do suma:= a+b; b:= a; a:= suma; end for end if return sum; end function algorithm main var number: integer; end var writeString("Introduce un número entero positivo: "); number:= readInteger() writeString("La suma de los "); writeInteger(number); writeString(" primeros números de la serie Fibonacci es: "); writeInteger(fibonacci(n)); end algorithm ``` 2. Solución ```alg const SALDO_INICIAL: real = 0.0; end const action actualizarsaldo(inout saldo: real, in cargo: real) saldo:= saldo + cargo; end action algorithm main var saldo, cargo: real; continuar: string; end var saldo:= SALDO_INICIAL; writeString("[i] El saldo actual de la cuenta corriente es de "); writeReal(saldo); writeString(" Petrodolares"); while continuar = "n" do writeString("[+] Introduce el cargo o imposición: "); cargo:= readReal(); actualizarsaldo(saldo, cargo); writeString("[i] El saldo actual de la cuenta corriente es de "); writeReal(saldo); writeString(" Petrodolares"); writeString("[+] Quiere realizar otra operación? (s/n): "); continuar:= readString(); end while end algorithm ``` 3. Solución ```alg function potencia(n: real, m: integer): real var i: integer; resultado: real; end var resultado:= 1.0; for i:= 1 to m do resultado:= resultado * n; end for return resultado; end function algorithm main var base, resultado: real; exponente: integer; end var writeString("[+] Introduce la base: "); base:= readReal(); writeString("[+] Introduce el exponente: "); exponente:= readInteger(); writeString("[i] El resultado de elevar "); writeReal(base); writeString(" a la potencia "); writeInteger(exponente); writeString(" es: "); writeReal(potencia(base, exponente)); end algorithm ``` 4. Solución ```alg function squareRoot(x: real): real var estimacion, epsilon: real; end var estimacion:= x / 2.0; epsilon:= 0.0001; while (((estimacion * estimacion - x) > epsilon) or (x - estimacion * estimacion) > epsilon) do estimacion:= (estimacion + x / estimacion) / 2.0; end while return estimacion; end function action calcularRaices(in A: real, in B: real, in C: real, out raiz1: real, out raiz2: real) var discriminante: real; end var discriminante:= B * B - 4 * A * C; if discriminante >= 0 then var raiz_discriminante: real; end var raiz_discriminante:= squareRoot(discriminante); raiz1:= (-B + raiz_discriminante) / (2 * A); raiz2:= (-B - raiz_discriminante) / (2 * A); else raiz1:= 0; raiz2:= 0; end if end action algorithm main var coeficiente_A, coeficiente_B, coeficiente_C, raiz1, raiz2: real; end var writeString("Introduce los coeficientes de la ecuación de segundo grado."); writeString("A: "); coeficiente_A:= readReal(); writeString("B: "); coeficiente_B:= readReal(); writeString("C: "); coeficiente_C:= readReal(); calcularRaices(coeficiente_A, coeficiente_B, coeficiente_C, raiz1, raiz2); writeString("Las raíces son: "); writeReal(raiz1); writeString(" y "); writeReal(raiz2); end algorithm ``` 5. Solución ```alg function calcularCostePintura(altura: real, anchura: real, precio_pintura: real): real return altura * anchura * precio_pintura; end function action calcularConsumoAgua(inout consumo_actual: real, inout meses_consumo_actual: integer, inout ano_consumo_actual: integer) var consumo_mes: real; meses_a_introducir: integer; end var writeString("¿Cuántos meses quieres introducir? "); meses_a_introducir:= readInteger(); for i:= 1 to meses_a_introducir do if meses_consumo_actual = 12 then meses_consumo_actual:= 1; ano_consumo_actual:= ano_consumo_actual + 1; else meses_consumo_actual:= meses_consumo_actual + 1; end if writeString("Introduce el consumo de agua del mes "); writeString(meses_consumo_actual); writeString(": "); readReal(consumo_mes); consumo_actual:= consumo_actual + consumo_mes; end for end action function calcularMesString(mes: integer): string var meses: array[1..12] of string; end var meses[1]:= "Enero"; meses[2]:= "Febrero"; meses[3]:= "Marzo"; meses[4]:= "Abril"; meses[5]:= "Mayo"; meses[6]:= "Junio"; meses[7]:= "Julio"; meses[8]:= "Agosto"; meses[9]:= "Septiembre"; meses[10]:= "Octubre"; meses[11]:= "Noviembre"; meses[12]:= "Diciembre"; return meses[mes]; end function action intercambiarValores(inout a: integer, inout b: integer) var temp: integer; end var if a ≠ 0 and b ≠ 0 then temp:= a; a:= b; b:= temp; end if end action function sumaDivisores(n: integer): integer var suma, i: integer; end var suma:= 0; for i:= 1 to n do if n mod i = 0 then suma:= suma + i; end if end for return suma; end function algorithm main var opcion: integer; consumo_actual: real; meses_consumo_actual, ano_consumo_actual: integer; end var consumo_actual:= 60; meses_consumo_actual:= 6; ano_consumo_actual:= 2021; repeat writeString("[+] Elige una opción:"); writeString("1. Calcular el coste total de pintura necesario para pintar una pared"); writeString("2. Calcular el consumo total de agua acumulado"); writeString("3. Intercambiar los valores de dos números enteros"); writeString("4. Calcular la suma de los divisores de un número entero"); writeString("5. Salir"); writeString("> "); readInteger(opcion); case opcion of 1: var altura, anchura, precio_pintura: real; end var writeString("[+] Introduce la altura de la pared: "); readReal(altura); writeString("[+] Introduce la anchura de la pared: "); readReal(anchura); writeString("[+] Introduce el precio de la pintura por metro cuadrado: "); readReal(precio_pintura); writeString("[+] El coste total de pintura necesario para pintar la pared es de "); writeReal(calcularCostePintura(altura, anchura, precio_pintura)); writeString(" euros"); 2: calcularConsumoAgua(consumo_actual, meses_consumo_actual, ano_consumo_actual); writeString("[+] El consumo total de agua acumulado hasta "); writeString(calcularMesString(meses_consumo_actual)); writeString(" del año "); writeInteger(ano_consumo_actual); writeString(" es de "); writeReal(consumo_actual); writeString(" litros"); 3: var num1, num2: integer; end var writeString("[+] Introduce el primer número entero: "); readInteger(num1); writeString("[+] Introduce el segundo número entero: "); readInteger(num2); intercambiarValores(num1, num2); writeString("[+] Los valores intercambiados son: "); writeInteger(num1); writeString(" y "); writeInteger(num2); 4: var numero: integer; end var writeString("[+] Introduce un número entero: "); readInteger(numero); writeString("[+] La suma de los divisores de "); writeInteger(numero); writeString(" es: "); writeInteger(sumaDivisores(numero)); 5: writeString("[!] Saliendo..."); otherwise writeString("[!] Opción no válida"); end case until opcion = 5 end algorithm ``` [Volver arriba](#pr-2)