From 61209b0ff961432b1f8da8dce2d280e74528a923 Mon Sep 17 00:00:00 2001 From: dcsibon Date: Sun, 10 Nov 2024 12:11:44 +0100 Subject: [PATCH] =?UTF-8?q?Ex=C3=A1menes=20de=20DAW1B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- daw1b_calculadora/abel_calculadora_alumnos.py | 364 +++++++++++ .../adrian_calculadora_alumnos.py | 476 +++++++++++++++ .../alejandro_calculadora_alumnos.py | 485 +++++++++++++++ .../alfonso_calculadora_alumnos.py | 505 +++++++++++++++ .../alfonso_calculadora_alumnos_bonus.py | 505 +++++++++++++++ .../angel_calculadora_alumnos.py | 428 +++++++++++++ .../antonio_calculadora_alumnos.py | 401 ++++++++++++ daw1b_calculadora/beni_calculadora_alumnos.py | 574 ++++++++++++++++++ .../daniel_calculadora_alumnos.py | 522 ++++++++++++++++ .../david_calculadora_alumnos.py | 521 ++++++++++++++++ .../ezequiel_calculadora_alumnos.py | 548 +++++++++++++++++ .../ezequiel_calculadora_alumnos_bonus.py | 551 +++++++++++++++++ daw1b_calculadora/inda_calculadora_alumnos.py | 401 ++++++++++++ .../jangel_calculadora_alumnos.py | 413 +++++++++++++ .../jantonio_calculadora_alumnos.py | 423 +++++++++++++ daw1b_calculadora/juan_calculadora_alumnos.py | 479 +++++++++++++++ .../pablo_calculadora_alumnos.py | 58 +- .../rocio_calculadora_alumnos.py | 498 +++++++++++++++ daw1b_calculadora/rocio_test_calculadora.py | 73 +++ .../sergio_calculadora_alumnos.py | 539 ++++++++++++++++ daw1b_calculadora/test_adrian_calculadora.py | 68 +++ daw1b_calculadora/test_beni_calculadora.py | 74 +++ daw1b_calculadora/test_daniel_calculadora.py | 74 +++ daw1b_calculadora/test_david_calculadora.py | 74 +++ daw1b_calculadora/test_inda_calculadora.py | 73 +++ daw1b_calculadora/test_jangel_calculadora.py | 80 +++ daw1b_calculadora/test_sergio_calculadora.py | 70 +++ daw1b_calculadora/test_victor_calculadora.py | 70 +++ .../victor_calculadora_alumnos.py | 473 +++++++++++++++ tests/test_calculadora_alumnos.py | 9 + 30 files changed, 9812 insertions(+), 17 deletions(-) create mode 100644 daw1b_calculadora/abel_calculadora_alumnos.py create mode 100644 daw1b_calculadora/adrian_calculadora_alumnos.py create mode 100644 daw1b_calculadora/alejandro_calculadora_alumnos.py create mode 100644 daw1b_calculadora/alfonso_calculadora_alumnos.py create mode 100644 daw1b_calculadora/alfonso_calculadora_alumnos_bonus.py create mode 100644 daw1b_calculadora/angel_calculadora_alumnos.py create mode 100644 daw1b_calculadora/antonio_calculadora_alumnos.py create mode 100644 daw1b_calculadora/beni_calculadora_alumnos.py create mode 100644 daw1b_calculadora/daniel_calculadora_alumnos.py create mode 100644 daw1b_calculadora/david_calculadora_alumnos.py create mode 100644 daw1b_calculadora/ezequiel_calculadora_alumnos.py create mode 100644 daw1b_calculadora/ezequiel_calculadora_alumnos_bonus.py create mode 100644 daw1b_calculadora/inda_calculadora_alumnos.py create mode 100644 daw1b_calculadora/jangel_calculadora_alumnos.py create mode 100644 daw1b_calculadora/jantonio_calculadora_alumnos.py create mode 100644 daw1b_calculadora/juan_calculadora_alumnos.py create mode 100644 daw1b_calculadora/rocio_calculadora_alumnos.py create mode 100644 daw1b_calculadora/rocio_test_calculadora.py create mode 100644 daw1b_calculadora/sergio_calculadora_alumnos.py create mode 100644 daw1b_calculadora/test_adrian_calculadora.py create mode 100644 daw1b_calculadora/test_beni_calculadora.py create mode 100644 daw1b_calculadora/test_daniel_calculadora.py create mode 100644 daw1b_calculadora/test_david_calculadora.py create mode 100644 daw1b_calculadora/test_inda_calculadora.py create mode 100644 daw1b_calculadora/test_jangel_calculadora.py create mode 100644 daw1b_calculadora/test_sergio_calculadora.py create mode 100644 daw1b_calculadora/test_victor_calculadora.py create mode 100644 daw1b_calculadora/victor_calculadora_alumnos.py diff --git a/daw1b_calculadora/abel_calculadora_alumnos.py b/daw1b_calculadora/abel_calculadora_alumnos.py new file mode 100644 index 0000000..e73426d --- /dev/null +++ b/daw1b_calculadora/abel_calculadora_alumnos.py @@ -0,0 +1,364 @@ +# TODO: ATENCIÓN!!! +# 1. Importar los paquetes necesarios +# 2. Usar la función mostrar_error para imprimir los errores por consola. +# 3. Los comentarios TODO os ayudan a resolver cada apartado de esta prueba. +# 4. CADA función SOLO puede tener una instrucción return. +# 5. En test_calculadora_alumnos.py crear el test unitario para la función es_resultado_negativo y hacer que todos los test unitarios se cumplan. + +import time +import os + +# Mensajes de error predefinidos +MENSAJES_ERROR = ( + "Problemas al intentar limpiar la pantalla {error}", + "Error al configurar los decimales. Formato: decimales .", + "Entrada no válida. Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo.", + "Error: Introduzca un operador antes de otro número.", + "Comando no reconocido. Escriba 'lista' para ver las operaciones disponibles.", + "Error: no es posible la división por 0! Introduzca otro valor diferente a 0...", + "Se produjo un error: {error}" +) + +# Operadores soportados por la calculadora +OPERADORES = +# TODO: Ayuda: incluye en esta constante los símbolos que reconocerá la aplicación para el cálculo de las operaciones: +# '+' para la suma. +# '-' para la resta. +# 'x' o '*' para la multiplicación. +# '/' o ':' para la división. +# '**' o 'exp' para la potencia. + + + +def limpiar_pantalla(): + """ + Limpia la consola según el sistema operativo. + """ + # TODO: El desarrollo de esta función está incompleto y con errores. + try: + if os.name == "poxis": + os.system("clear") + else: + os.system("cls") + except Exception as e: + mostrar_error(f"Problemas al intentar limpiar la pantalla: {e}") + + # Otra forma de expresar la misma instrucción sería la siguiente: + # if os.name = posix: + # os.system(clear) + # else: + # os.system(cls) + + +def pausa(tiempo :int, tecla_enter :False): + """ + Pausa la ejecución del programa hasta que se pulse ENTER... "\nPresione ENTER para continuar..." + """ + # TODO: Desarrollar esta función según su documentación. + if tiempo != 0: + time.sleep(tiempo) + elif tecla_enter == False: + input("\nPresione ENTER para continuar...") + +def mostrar_error(indice_error: int, msj_error = None): + """ + Muestra un mensaje de error en la consola. + + Args: + indice_error (int): Índice del mensaje de error en MENSAJES_ERROR. + msj_error (str, opcional): Texto adicional para personalizar el mensaje de error. + """ + # TODO: + # 1. Corrige el error que existe a la hora de acceder a los mensajes de error que están en la constante + # MENSAJES_ERROR. A los elementos de una tupla se accede igual que a los caracteres de una + # cadena de caracteres. + # 2. Completa el código de esta función para que controle específicamente las excepciones IndexError y + # muestre el mensaje: "\n*ERROR* Mensaje de error no definido.\n" + # 3. También se pide que se controle cualquier otra excepción que se pueda producir y muestre el mensaje: + # "\n*ERROR* Problemas al mostrar error!\n{e}\n" + # 4. En esta función los mensajes de error deben mostrarse con print. + if msj_error != None: + print(f"\n*ERROR* {MENSAJES_ERROR.format(error = msj_error)}\n") + else: + print(f"\n*ERROR* {MENSAJES_ERROR}\n") + + +def sumar(): + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la suma de ambos. + + + +def restar(): + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la resta de ambos. + + + +def es_resultado_negativo(num1: float, num2: float) -> bool: + """Determina si el resultado de una operación entre num1 y num2 debe ser negativo.""" + # TODO: Realizar el desarrollo completo de esta función teniendo en cuenta la documentación y completándola también. + # Debe pasar las pruebas unitarias. + # Se trata de una función que os puede venir bien para utilizarla tanto en la función multiplicar, como en dividir. + # Ya que va a determinar si la multiplicación o división entre dos números debería ser de signo negativo o no. + + + +def multiplicar(): + """ + Realiza la multiplicación ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la multiplicación. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de multiplicación de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la multiplicación con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 * 3.33, deberá convertirse en 5 * 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 * -5 = 25 + # 6. OBLIGATORIO usar un bucle for. + # 7. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + + +def dividir(): + """ + Realiza la división ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Dividendo. + num2 (float): Divisor. + + Returns: + int: Resultado de la división. + + Raises: + ZeroDivisionError: Si el divisor es cero. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de división de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la división con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 / 3.33, deberá convertirse en 5 / 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 / -5 = 1 + # 6. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + +def potencia(): + # TODO: + # 1. Realizar el desarrollo completo de esta función y su documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. PREMISAS a tener en cuenta: + # - Cualquier número elevado a 0 da como resultado 1. + # - Para simplificar esta función, vamos a suponer que un número elevado a un + # exponente negativo siempre dará 0 (aunque en realidad no es así matemáticamente) + # 4. Utiliza la función de multiplicar para realizar los cálculos que te + # harán falta en esta función (RECUERDA que no puedes usar directamente los operadores + # de Python para la multiplicación y división). + # 5. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + +def pedir_entrada(msj: str) -> str: + """ + Pide al usuario una entrada, elimina espacios por delante y por detrás y la convierte a minúsculas. + + Args: + msj (str): Mensaje para solicitar la entrada. + + Returns: + str: Entrada del usuario. + """ + # TODO: El desarrollo de esta función está incompleto, debéis terminarla teniendo en cuenta la documentación + return input(msj) + + +def calcular_operacion(num1: float, num2: float, operador: str) -> float: + """ + Realiza la operación especificada entre num1 y num2 dependiendo del valor del operador. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + float: Resultado de la operación. + + Raises: + ZeroDivisionError: Si el divisor es cero. + """ + # TODO: El desarrollo de esta función está incompleto... completadla teniendo en cuenta la documentación + # y que debe realizar las llamadas adecuadas a las funciones ya creadas para realizar los distintos + # cálculos... sumar, restar, multiplicar, dividir y potencia. + # IMPORTANTE: Si hacemos caso a la documentación de esta función, NO debéis capturar la excepción + # ZeroDivisionError aquí, sino que hay que dejadla que se propague a la función llamante, realizar_calculo(), + # dónde se os indica cómo realizar la gestión de estos errores. + + return resultado + + + +def obtener_operaciones() -> str: + """ + Devuelve una cadena con la lista de operaciones disponibles en la calculadora. + + Returns: + (str): cadena de caracteres con la información de las operaciones disponibles. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + """ + Operaciones disponibles: + ce => Reiniciar resultado a 0 + decimales => Establecer decimales en resultado + cadena vacía + => Pregunta si desea salir + calculo => Iniciar cálculo secuencial + + => Suma + - => Resta + x o * => Multiplicación + / o : => División + ** o exp => Potencia + cancelar => vovler sin actualizar resultado de la calculadora + cadena vacía + => volver actualizando resultado de la calculadora + """ + + +def realizar_calculo(): + """ + Realiza una secuencia de cálculos solicitando números y operadores al usuario. + + Args: + decimales (int): Número de decimales para el resultado. + resultado_almacenado (float): Valor almacenado en la calculadora. + + Returns: + float: Resultado final del cálculo o None si se cancela. + + Note: + * Dentro de esta función el usuario puede realizar cálculos secuenciales, es decir, + comenzará introduciendo un número, después un operador, y otro número... a partir + de aquí sobre el resultado acumulado, introducirá operador y número para seguir + realizando cálculos (ver ejemplos en README.md de la tarea en el repositorio de GitHub). + * El usuario es guiado para introducir números y operadores secuencialmente + para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el + resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado + de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el + resultado almacenado de la calculadora. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + + operador = None + resultado = None + realizando_calculos = True + + print("\n## Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo ##\n") + + while realizando_calculos: + entrada = pedir_entrada(f"\t (Cálculo = resultado) >> ") + + if entrada == "cancelar": + + + elif entrada == "": + + + elif entrada in OPERADORES: + operador = + + else: + # TODO: este código funciona cuando solucionéis que reconozca las variables resultado_almacenado y decimales. + # Pero no gestiona los posibles tipos de Excepciones que se pueden producir: + # - ValueError que debe mostrar el error que está en la posición 2 de MENSAJES_ERROR. + # - ZeroDivisionError que debe mostrar el error que está en la posición 5 de MENSAJES_ERROR. + # - Exception que debe mostrar el error que está en la posición 6 de MENSAJES_ERROR. + if entrada == "resultado": + entrada = resultado_almacenado + + try: + numero = float(entrada) + + if operador is not None: + if resultado is None: + resultado = 0 + resultado = round(calcular_operacion(resultado, numero, operador), decimales) + operador = None + + elif resultado is None: + resultado = numero + + else: + mostrar_error(3) + except + + +def main(): + """ + Función principal de la calculadora. Gestiona la entrada del usuario y coordina las operaciones. + + Note: + El flujo del programa es el siguiente: + + 1. Inicia la calculadora mostrando el resultado almacenado por defecto (0.00). + + 2. El usuario ingresa un comando, que puede ser: + - "lista" para ver todas las operaciones disponibles. + - "ce" para reiniciar el resultado almacenado a 0. + - "decimales " para establecer el número de decimales mostrados en el resultado. + - "calculo" para iniciar una secuencia de cálculo paso a paso. + - Una entrada vacía y pulsa la tecla para salir de la calculadora. + + 3. Según el comando ingresado: + - El programa realiza la operación o ejecuta la acción indicada. + - Al ingresar "calculo": + * El usuario es guiado para introducir números y operadores secuencialmente para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el resultado almacenado de la calculadora. + + 4. La calculadora sigue ejecutándose hasta que el usuario confirma la salida al ingresar una entrada vacía y pulsar . + + 5. Finalmente, se limpia la pantalla, el programa se despide con el mensaje "\n\nBye, bye...\n\n" y termina. + """ + # TODO: Corrige los errores y haz que el main funcione correctamente... + + decimales = 2 + resultado = 0.0 + + while not desea_salir: + + pedir_entrada(f"Operación (RES => ({resultado}) >> ") + + if entrada == "": + pedir_entrada("¿Desea salir de la calculadora? (s/n) ") + + elif entrada == "lista": + obtener_operaciones + + elif entrada == "ce": + + + elif entrada.startswith("decimales"): + # Extraemos las posiciones decimales y las convertimos a un valor entero + decimales = str(entrada.split()[1]) + print(f"Decimales configurados a {decimales}.") + + elif entrada == "calculo": + realizar_calculo(decimales, resultado) + + else: + mostrar_error diff --git a/daw1b_calculadora/adrian_calculadora_alumnos.py b/daw1b_calculadora/adrian_calculadora_alumnos.py new file mode 100644 index 0000000..0a3f828 --- /dev/null +++ b/daw1b_calculadora/adrian_calculadora_alumnos.py @@ -0,0 +1,476 @@ +# TODO: ATENCIÓN!!! +# 1. Importar los paquetes necesarios +# 2. Usar la función mostrar_error para imprimir los errores por consola. +# 3. Los comentarios TODO os ayudan a resolver cada apartado de esta prueba. +# 4. CADA función SOLO puede tener una instrucción return. +# 5. En test_calculadora_alumnos.py crear el test unitario para la función es_resultado_negativo y hacer que todos los test unitarios se cumplan. + +import os +import keyboard +import format + + +# Mensajes de error predefinidos +MENSAJES_ERROR = ( + "Problemas al intentar limpiar la pantalla {error}", + "Error al configurar los decimales. Formato: decimales .", + "Entrada no válida. Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo.", + "Error: Introduzca un operador antes de otro número.", + "Comando no reconocido. Escriba 'lista' para ver las operaciones disponibles.", + "Error: no es posible la división por 0! Introduzca otro valor diferente a 0...", + "Se produjo un error: {error}" +) + +# Operadores soportados por la calculadora +OPERADORES = ["+", "-", "x", "*", "/", ":", "**", "exp"] +# TODO: Ayuda: incluye en esta constante los símbolos que reconocerá la aplicación para el cálculo de las operaciones: +# '+' para la suma. +# '-' para la resta. +# 'x' o '*' para la multiplicación. +# '/' o ':' para la división. +# '**' o 'exp' para la potencia. + + + +def limpiar_pantalla(): + """ + Limpia la consola según el sistema operativo. + """ + # TODO: El desarrollo de esta función está incompleto y con errores. + try: + if os.name("posix"): + os.system("clear") + else: + os.system("cls") + # Otra forma de expresar la misma instrucción sería la siguiente: + # if os.name = posix: + # os.system(clear) + # else: + # os.system(cls) + except Exception as e: + raise("Problemas al intentar limpiar la pantalla {error}") + + +def pausa(): + """ + Pausa la ejecución del programa hasta que se pulse ENTER... "\nPresione ENTER para continuar..." + """ + # TODO: Desarrollar esta función según su documentación. + print("\nPresione ENTER para continuar...") + while True: + if keyboard.is_pressed("enter"): + break + else: + continue + + + +def mostrar_error(indice_error: int, msj_error = None): + """ + Muestra un mensaje de error en la consola. + + Args: + indice_error (int): Índice del mensaje de error en MENSAJES_ERROR. + msj_error (str, opcional): Texto adicional para personalizar el mensaje de error. + """ + # TODO: + # 1. Corrige el error que existe a la hora de acceder a los mensajes de error que están en la constante + # MENSAJES_ERROR. A los elementos de una tupla se accede igual que a los caracteres de una + # cadena de caracteres. + # 2. Completa el código de esta función para que controle específicamente las excepciones IndexError y + # muestre el mensaje: "\n*ERROR* Mensaje de error no definido.\n" + # 3. También se pide que se controle cualquier otra excepción que se pueda producir y muestre el mensaje: + # "\n*ERROR* Problemas al mostrar error!\n{e}\n" + # 4. En esta función los mensajes de error deben mostrarse con print. + if msj_error != None: + print(f"\n*ERROR* {MENSAJES_ERROR.format(error = msj_error)}\n") + else: + print(f"\n*ERROR* {MENSAJES_ERROR}\n") + + +def sumar(num1, num2): + """Realiza las suma de los 2 numeros proporcionados + + Args: + num1 (float): 1º Numero real introducido por el usuario + num2 (float): 2º Numero real introducido por el usuario + + Returns: + float: La suma de ambos numeros + """ + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la suma de ambos. + + suma = float(num1+num2) + + return suma + +def restar(num1, num2): + """Realiza la resta de los 2 numeros proporcionados + + Args: + num1 (float): 1º Numero real introducido por el usuario + num2 (float): 2º Numero real introducido por el usuario + + Returns: + float: La resta de ambos numeros + """ + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la resta de ambos. + + resta = float(num1 - num2) + + return resta + + +def es_resultado_negativo(num1: float, num2: float) -> bool: + """Determina si el resultado de una operación entre num1 y num2 debe ser negativo.""" + # TODO: Realizar el desarrollo completo de esta función teniendo en cuenta la documentación y completándola también. + # Debe pasar las pruebas unitarias. + # Se trata de una función que os puede venir bien para utilizarla tanto en la función multiplicar, como en dividir. + # Ya que va a determinar si la multiplicación o división entre dos números debería ser de signo negativo o no. + + if num1 < 0 and num2 > 0 or num1 > 0 and num2 < 0: + a = True + else: + a = False + return a + + +# TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de multiplicación de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la multiplicación con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 * 3.33, deberá convertirse en 5 * 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 * -5 = 25 + # 6. OBLIGATORIO usar un bucle for. + # 7. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + +def multiplicar(num1:str, num2:str): + """ + Realiza la multiplicación ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la multiplicación. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + num1 = str(num1) + num2 = str(num2) + signo = es_resultado_negativo(float(num1), float(num2)) + num1 = num1.replace("-", "") + num2 = num2.replace("-", "") + num1 = float(num1) + num1 = int(num1) + num2 = int(num2) + if num1 == 0 or num2 == 0: + resultado = 0 + else: + if num1 > num2: + resultado = num1 + for i in range(0, num2-1, +1): + resultado = resultado+num1 + else: + resultado = num2 + for i in range(0, num1-1,+1): + resultado = resultado+int(num2) + if signo == True: + s = "-" + resultado = s+str(resultado) + resultado = float(resultado) + return resultado + +# TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de división de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la división con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 / 3.33, deberá convertirse en 5 / 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 / -5 = 1 + # 6. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + +def dividir(num1, num2): + """ + Realiza la división ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Dividendo. + num2 (float): Divisor. + + Returns: + int: Resultado de la división. + + Raises: + ZeroDivisionError: Si el divisor es cero. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + contador = 0 + num1 = str(num1) + num2 = str(num2) + signo = es_resultado_negativo(float(num1), float(num2)) + num1 = num1.replace("-", "") + num2 = num2.replace("-", "") + num1 = float(num1) + num2 = float(num2) + num1 = int(round(num1,0)) + num2 = int(round(num2, 0)) + + if num1 == 0 or num2 == 0: + raise(ZeroDivisionError) + else: + resultado = num1 + # Esto va restando el resultado hasta que es menor que 0 por lo cual implica que ya no se puede continuar dividiendo y tienes el resultado + while resultado >= 0: + resultado -= num2 + if resultado >= 0: + contador += 1 + if signo == True: + s = "-" + contador = float(s + str(contador)) + return contador + +# TODO: + # 1. Realizar el desarrollo completo de esta función y su documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. PREMISAS a tener en cuenta: + # - Cualquier número elevado a 0 da como resultado 1. + # - Para simplificar esta función, vamos a suponer que un número elevado a un + # exponente negativo siempre dará 0 (aunque en realidad no es así matemáticamente) + # 4. Utiliza la función de multiplicar para realizar los cálculos que te + # harán falta en esta función (RECUERDA que no puedes usar directamente los operadores + # de Python para la multiplicación y división). + # 5. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + +def potencia(num1, num2): + """Esto realiza la potencia dada por el usuario usando la funcion de multiplicar + + Args: + num1 (float): 1º Numero real introducido por el usuario + num2 (float): 2º Numero real introducido por el usuario + + Returns: + float: Te devuelve el resultado de la potencia + """ + + if num2 == 0: + resultado = 1 + elif num2 < 0: + resultado = 0 + elif num2 == 1: + resultado = num1 + else: + for i in range(1, num2, +1): + if i == 1: + resultado = multiplicar(num1, num1) + else: + resultado = multiplicar(resultado, num1) + resultado = float(resultado) + return resultado + + +def pedir_entrada(msj: str) -> str: + """ + Pide al usuario una entrada, elimina espacios por delante y por detrás y la convierte a minúsculas. + + Args: + msj (str): Mensaje para solicitar la entrada. + + Returns: + str: Entrada del usuario. + """ + # TODO: El desarrollo de esta función está incompleto, debéis terminarla teniendo en cuenta la documentación + + num = str(input(msj)) + num = num.replace(" ", "") + num = num.lower() + + return num + + +def calcular_operacion(num1: float, num2: float, operador: str) -> float: + """ + Realiza la operación especificada entre num1 y num2 dependiendo del valor del operador. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + float: Resultado de la operación. + + Raises: + ZeroDivisionError: Si el divisor es cero. + """ + # TODO: El desarrollo de esta función está incompleto... completadla teniendo en cuenta la documentación + # y que debe realizar las llamadas adecuadas a las funciones ya creadas para realizar los distintos + # cálculos... sumar, restar, multiplicar, dividir y potencia. + # IMPORTANTE: Si hacemos caso a la documentación de esta función, NO debéis capturar la excepción + # ZeroDivisionError aquí, sino que hay que dejadla que se propague a la función llamante, realizar_calculo(), + # dónde se os indica cómo realizar la gestión de estos errores. + + return resultado + + + +def obtener_operaciones() -> str: + """ + Devuelve una cadena con la lista de operaciones disponibles en la calculadora. + + Returns: + (str): cadena de caracteres con la información de las operaciones disponibles. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + """ + Operaciones disponibles: + ce => Reiniciar resultado a 0 + decimales => Establecer decimales en resultado + cadena vacía + => Pregunta si desea salir + calculo => Iniciar cálculo secuencial + + => Suma + - => Resta + x o * => Multiplicación + / o : => División + ** o exp => Potencia + cancelar => vovler sin actualizar resultado de la calculadora + cadena vacía + => volver actualizando resultado de la calculadora + """ + + +def realizar_calculo(): + """ + Realiza una secuencia de cálculos solicitando números y operadores al usuario. + + Args: + decimales (int): Número de decimales para el resultado. + resultado_almacenado (float): Valor almacenado en la calculadora. + + Returns: + float: Resultado final del cálculo o None si se cancela. + + Note: + * Dentro de esta función el usuario puede realizar cálculos secuenciales, es decir, + comenzará introduciendo un número, después un operador, y otro número... a partir + de aquí sobre el resultado acumulado, introducirá operador y número para seguir + realizando cálculos (ver ejemplos en README.md de la tarea en el repositorio de GitHub). + * El usuario es guiado para introducir números y operadores secuencialmente + para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el + resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado + de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el + resultado almacenado de la calculadora. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + + operador = None + resultado = None + realizando_calculos = True + + print("\n## Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo ##\n") + + while realizando_calculos: + entrada = pedir_entrada(f"\t (Cálculo = resultado) >> ") + + if entrada == "cancelar": + + + elif entrada == "": + + + elif entrada in OPERADORES: + operador = + + else: + # TODO: este código funciona cuando solucionéis que reconozca las variables resultado_almacenado y decimales. + # Pero no gestiona los posibles tipos de Excepciones que se pueden producir: + # - ValueError que debe mostrar el error que está en la posición 2 de MENSAJES_ERROR. + # - ZeroDivisionError que debe mostrar el error que está en la posición 5 de MENSAJES_ERROR. + # - Exception que debe mostrar el error que está en la posición 6 de MENSAJES_ERROR. + if entrada == "resultado": + entrada = resultado_almacenado + + try: + numero = float(entrada) + + if operador is not None: + if resultado is None: + resultado = 0 + resultado = round(calcular_operacion(resultado, numero, operador), decimales) + operador = None + + elif resultado is None: + resultado = numero + + else: + mostrar_error(3) + except + + +def main(): + """ + Función principal de la calculadora. Gestiona la entrada del usuario y coordina las operaciones. + + Note: + El flujo del programa es el siguiente: + + 1. Inicia la calculadora mostrando el resultado almacenado por defecto (0.00). + + 2. El usuario ingresa un comando, que puede ser: + - "lista" para ver todas las operaciones disponibles. + - "ce" para reiniciar el resultado almacenado a 0. + - "decimales " para establecer el número de decimales mostrados en el resultado. + - "calculo" para iniciar una secuencia de cálculo paso a paso. + - Una entrada vacía y pulsa la tecla para salir de la calculadora. + + 3. Según el comando ingresado: + - El programa realiza la operación o ejecuta la acción indicada. + - Al ingresar "calculo": + * El usuario es guiado para introducir números y operadores secuencialmente para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el resultado almacenado de la calculadora. + + 4. La calculadora sigue ejecutándose hasta que el usuario confirma la salida al ingresar una entrada vacía y pulsar . + + 5. Finalmente, se limpia la pantalla, el programa se despide con el mensaje "\n\nBye, bye...\n\n" y termina. + """ + # TODO: Corrige los errores y haz que el main funcione correctamente... + + decimales = 2 + resultado = 0.0 + + while not desea_salir: + + pedir_entrada(f"Operación (RES => resultado) >> ") + + if entrada == "": + pedir_entrada("¿Desea salir de la calculadora? (s/n) ") + + elif entrada == "lista": + obtener_operaciones + + elif entrada == "ce": + + + elif entrada.startswith("decimales"): + # Extraemos las posiciones decimales y las convertimos a un valor entero + decimales = str(entrada.split()[1]) + print(f"Decimales configurados a {decimales}.") + + elif entrada == "calculo": + realizar_calculo(decimales, resultado) + + else: + mostrar_error diff --git a/daw1b_calculadora/alejandro_calculadora_alumnos.py b/daw1b_calculadora/alejandro_calculadora_alumnos.py new file mode 100644 index 0000000..a259422 --- /dev/null +++ b/daw1b_calculadora/alejandro_calculadora_alumnos.py @@ -0,0 +1,485 @@ +# TODO: ATENCIÓN!!! +# 1. Importar los paquetes necesarios +# 2. Usar la función mostrar_error para imprimir los errores por consola. +# 3. Los comentarios TODO os ayudan a resolver cada apartado de esta prueba. +# 4. CADA función SOLO puede tener una instrucción return. +# 5. En test_calculadora_alumnos.py crear el test unitario para la función es_resultado_negativo y hacer que todos los test unitarios se cumplan. + +import time +import os + +# Mensajes de error predefinidos +MENSAJES_ERROR = ( + "Problemas al intentar limpiar la pantalla {error}", + "Error al configurar los decimales. Formato: decimales .", + "Entrada no válida. Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo.", + "Error: Introduzca un operador antes de otro número.", + "Comando no reconocido. Escriba 'lista' para ver las operaciones disponibles.", + "Error: no es posible la división por 0! Introduzca otro valor diferente a 0...", + "Se produjo un error: {error}" +) + +# Operadores soportados por la calculadora +OPERADORES = ("+","-","x","*","/",":","**","exp") +# TODO: Ayuda: incluye en esta constante los símbolos que reconocerá la aplicación para el cálculo de las operaciones: +# '+' para la suma. +# '-' para la resta. +# 'x' o '*' para la multiplicación. +# '/' o ':' para la división. +# '**' o 'exp' para la potencia. + + + +def limpiar_pantalla(): + """ + Limpia la consola según el sistema operativo. + """ + # TODO: El desarrollo de esta función está incompleto y con errores. + try: + if os.name == "nt": + os.system("cls") + elif os.name == "posix": + os.system(clear) + except Exception as error: + mostrar_error(0) + pausa() + + +def pausa(): + """ + Pausa la ejecución del programa hasta que se pulse ENTER... "\nPresione ENTER para continuar..." + """ + # TODO: Desarrollar esta función según su documentación. + input("\nPresione ENTER para continuar...") + + +def mostrar_error(indice_error: int, msj_error = None): + """ + Muestra un mensaje de error en la consola. + + Args: + indice_error (int): Índice del mensaje de error en MENSAJES_ERROR. + msj_error (str, opcional): Texto adicional para personalizar el mensaje de error. + """ + # TODO: + # 1. Corrige el error que existe a la hora de acceder a los mensajes de error que están en la constante + # MENSAJES_ERROR. A los elementos de una tupla se accede igual que a los caracteres de una + # cadena de caracteres. + # 2. Completa el código de esta función para que controle específicamente las excepciones IndexError y + # muestre el mensaje: "\n*ERROR* Mensaje de error no definido.\n" + # 3. También se pide que se controle cualquier otra excepción que se pueda producir y muestre el mensaje: + # "\n*ERROR* Problemas al mostrar error!\n{e}\n" + # 4. En esta función los mensajes de error deben mostrarse con print. + if msj_error != None: + print(f"\n*ERROR* {MENSAJES_ERROR.format(error = msj_error)}\n") + else: + print(f"\n*ERROR* {MENSAJES_ERROR[indice_error]}\n") + + +def sumar(num1 :float, num2 :float): + """ + + Realiza la suma entre dos numeros. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + float: Resultado de la suma + + """ + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la suma de ambos. + return (num1 + num2) + + +def restar(num1 :float, num2 :float) -> float: + """ + + Realiza la resta entre dos numeros. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + float: Resultado de la resta + + """ + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la resta de ambos. + return (num1 - num2) + +def es_resultado_negativo(num1: float, num2: float) -> bool: + """Determina si el resultado de una operación entre num1 y num2 debe ser negativo.""" + # TODO: Realizar el desarrollo completo de esta función teniendo en cuenta la documentación y completándola también. + # Debe pasar las pruebas unitarias. + # Se trata de una función que os puede venir bien para utilizarla tanto en la función multiplicar, como en dividir. + # Ya que va a determinar si la multiplicación o división entre dos números debería ser de signo negativo o no. + + + +def multiplicar(num1 :float, num2 :float) -> int: + """ + Realiza la multiplicación ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la multiplicación. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de multiplicación de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la multiplicación con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 * 3.33, deberá convertirse en 5 * 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 * -5 = 25 + # 6. OBLIGATORIO usar un bucle for. + # 7. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + num1 = int(num1) + num2 = int(num2) + resultado = 0 + + for i in range (num2): + resultado += num1 + return resultado + + +def dividir(num1 :float, num2 :float) -> int: + """ + Realiza la división ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Dividendo. + num2 (float): Divisor. + + Returns: + int: Resultado de la división. + + Raises: + ZeroDivisionError: Si el divisor es cero. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de división de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la división con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 / 3.33, deberá convertirse en 5 / 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 / -5 = 1 + # 6. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + num1 = round(num1,0) + num2 = round(num2,0) + resultado = 0 + + if num2 == 0: + raise ZeroDivisionError + + while num1 > 0: + num1 -= num2 + resultado += 1 + if num1 < 0: + resultado -=1 + resultado += 0.5 + + resultado += num1 + + return resultado + +def potencia(num1 :float, num2 :float) -> int: + """ + Realiza la potencia de dos números usando la funcion multiplicar que utiliza sumas. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la potencia. + + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función y su documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. PREMISAS a tener en cuenta: + # - Cualquier número elevado a 0 da como resultado 1. + # - Para simplificar esta función, vamos a suponer que un número elevado a un + # exponente negativo siempre dará 0 (aunque en realidad no es así matemáticamente) + # 4. Utiliza la función de multiplicar para realizar los cálculos que te + # harán falta en esta función (RECUERDA que no puedes usar directamente los operadores + # de Python para la multiplicación y división). + # 5. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + num1 = int(num1) + num2 = int(num2) + resultado = 0 + + if num2 == 0: + resultado = 1 + else: + for i in range (num2-1): + resultado += multiplicar(num1,num1) + + + return resultado + +def pedir_entrada(msj: str) -> str: + """ + Pide al usuario una entrada, elimina espacios por delante y por detrás y la convierte a minúsculas. + + Args: + msj (str): Mensaje para solicitar la entrada. + + Returns: + str: Entrada del usuario. + """ + # TODO: El desarrollo de esta función está incompleto, debéis terminarla teniendo en cuenta la documentación + return input(msj).strip().lower() + + +def calcular_operacion(num1: float, num2: float, operador: str) -> float: + """ + Realiza la operación especificada entre num1 y num2 dependiendo del valor del operador. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + float: Resultado de la operación. + + Raises: + ZeroDivisionError: Si el divisor es cero. + """ + # TODO: El desarrollo de esta función está incompleto... completadla teniendo en cuenta la documentación + # y que debe realizar las llamadas adecuadas a las funciones ya creadas para realizar los distintos + # cálculos... sumar, restar, multiplicar, dividir y potencia. + # IMPORTANTE: Si hacemos caso a la documentación de esta función, NO debéis capturar la excepción + # ZeroDivisionError aquí, sino que hay que dejadla que se propague a la función llamante, realizar_calculo(), + # dónde se os indica cómo realizar la gestión de estos errores. + + if operador == "+": + resultado = sumar(num1,num2) + elif operador == "-": + resultado = restar(num1,num2) + elif operador == "*" or operador == "x": + resultado = multiplicar(num1,num2) + elif operador == "/" or operador == ":": + resultado = dividir(num1,num2) + elif operador == "**" or operador == "exp": + resultado = potencia(num1,num2) + + return float(resultado) + + + +def obtener_operaciones() -> str: + """ + Devuelve una cadena con la lista de operaciones disponibles en la calculadora. + + Returns: + (str): cadena de caracteres con la información de las operaciones disponibles. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + return print( + """ + Operaciones disponibles: + ce => Reiniciar resultado a 0 + decimales => Establecer decimales en resultado + cadena vacía + => Pregunta si desea salir + calculo => Iniciar cálculo secuencial + + => Suma + - => Resta + x o * => Multiplicación + / o : => División + ** o exp => Potencia + cancelar => vovler sin actualizar resultado de la calculadora + cadena vacía + => volver actualizando resultado de la calculadora + """ + ) + + +def realizar_calculo(decimales :int, resultado_almacenado :float) -> float: + """ + Realiza una secuencia de cálculos solicitando números y operadores al usuario. + + Args: + decimales (int): Número de decimales para el resultado. + resultado_almacenado (float): Valor almacenado en la calculadora. + + Returns: + float: Resultado final del cálculo o None si se cancela. + + Note: + * Dentro de esta función el usuario puede realizar cálculos secuenciales, es decir, + comenzará introduciendo un número, después un operador, y otro número... a partir + de aquí sobre el resultado acumulado, introducirá operador y número para seguir + realizando cálculos (ver ejemplos en README.md de la tarea en el repositorio de GitHub). + * El usuario es guiado para introducir números y operadores secuencialmente + para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el + resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado + de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el + resultado almacenado de la calculadora. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + + operador = None + resultado = None + realizando_calculos = True + + print("\n## Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo ##\n") + + while realizando_calculos: + entrada = pedir_entrada(f"\t (Cálculo = {resultado}) >> ") + + if entrada == "cancelar": + realizando_calculos = False + + elif entrada == "": + realizando_calculos = False + + + elif entrada in OPERADORES: + operador = entrada + + else: + # TODO: este código funciona cuando solucionéis que reconozca las variables resultado_almacenado y decimales. + # Pero no gestiona los posibles tipos de Excepciones que se pueden producir: + # - ValueError que debe mostrar el error que está en la posición 2 de MENSAJES_ERROR. + # - ZeroDivisionError que debe mostrar el error que está en la posición 5 de MENSAJES_ERROR. + # - Exception que debe mostrar el error que está en la posición 6 de MENSAJES_ERROR. + if entrada == "resultado": + entrada = resultado_almacenado + + try: + numero = float(entrada) + + if operador is not None: + if resultado is None: + resultado = 0 + resultado = round(calcular_operacion(resultado, numero, operador), decimales) + operador = None + + elif resultado is None: + resultado = numero + + else: + mostrar_error(3) + pausa() + except Exception: + if numero == 0: + mostrar_error(5) + print("") + pausa() + elif numero == None: + mostrar_error(2) + print("") + pausa() + else: + mostrar_error(6) + print("") + pausa() + return float(resultado) + + +def main(): + """ + Función principal de la calculadora. Gestiona la entrada del usuario y coordina las operaciones. + + Note: + El flujo del programa es el siguiente: + + 1. Inicia la calculadora mostrando el resultado almacenado por defecto (0.00). + + 2. El usuario ingresa un comando, que puede ser: + - "lista" para ver todas las operaciones disponibles. + - "ce" para reiniciar el resultado almacenado a 0. + - "decimales " para establecer el número de decimales mostrados en el resultado. + - "calculo" para iniciar una secuencia de cálculo paso a paso. + - Una entrada vacía y pulsa la tecla para salir de la calculadora. + + 3. Según el comando ingresado: + - El programa realiza la operación o ejecuta la acción indicada. + - Al ingresar "calculo": + * El usuario es guiado para introducir números y operadores secuencialmente para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el resultado almacenado de la calculadora. + + 4. La calculadora sigue ejecutándose hasta que el usuario confirma la salida al ingresar una entrada vacía y pulsar . + + 5. Finalmente, se limpia la pantalla, el programa se despide con el mensaje "\n\nBye, bye...\n\n" y termina. + """ + # TODO: Corrige los errores y haz que el main funcione correctamente... + + decimales = 2 + resultado = 0.0 + desea_salir = False + + while not desea_salir: + + limpiar_pantalla() + print("\n\n### CALCULADORA ###\n\n") + + entrada = pedir_entrada(f"Operación (RES => {resultado}) >> ") + + if entrada == "": + desea_salir = pedir_entrada("¿Desea salir de la calculadora? (s/n) ") + if desea_salir == "s": + desea_salir = True + limpiar_pantalla() + print("\n\n\n\n Chao Pescaoooooo \n\n\n\n") + elif desea_salir == "n": + desea_salir = False + else: + print("Entrada invalida, tiene que ser **s** o **n**") + + + elif entrada == "lista": + obtener_operaciones() + pausa() + + elif entrada == "ce": + resultado = 0.0 + + elif entrada.startswith("decimales"): + # Extraemos las posiciones decimales y las convertimos a un valor entero + try: + decimales = int(entrada.split()[1]) + print(f"Decimales configurados a {decimales}.") + pausa() + except Exception: + mostrar_error(1) + pausa() + + elif entrada == "calculo": + resultado = realizar_calculo(decimales, resultado) + + else: + mostrar_error(4) + pausa() + + +if __name__ == "__main__": + main() + + + + + +# formatear el primer numero que sale despues de res=> para que salga con los decimales que tienen que salir que esten configurados \ No newline at end of file diff --git a/daw1b_calculadora/alfonso_calculadora_alumnos.py b/daw1b_calculadora/alfonso_calculadora_alumnos.py new file mode 100644 index 0000000..04b9676 --- /dev/null +++ b/daw1b_calculadora/alfonso_calculadora_alumnos.py @@ -0,0 +1,505 @@ +# TODO: ATENCIÓN!!! +# 1. Importar los paquetes necesarios +# 2. Usar la función mostrar_error para imprimir los errores por consola. +# 3. Los comentarios TODO os ayudan a resolver cada apartado de esta prueba. +# 4. CADA función SOLO puede tener una instrucción return. +# 5. En test_calculadora_alumnos.py crear el test unitario para la función es_resultado_negativo y hacer que todos los test unitarios se cumplan. +import os + + +# Mensajes de error predefinidos +MENSAJES_ERROR = ( + "Problemas al intentar limpiar la pantalla {error}", + "Error al configurar los decimales. Formato: decimales .", + "Entrada no válida. Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo.", + "Error: Introduzca un operador antes de otro número.", + "Comando no reconocido. Escriba 'lista' para ver las operaciones disponibles.", + "Error: no es posible la división por 0! Introduzca otro valor diferente a 0...", + "Se produjo un error: {error}" +) + +# Operadores soportados por la calculadora +OPERADORES = ["+", "-", "x", "*", "/", ":", "**", "exp"] +# TODO: Ayuda: incluye en esta constante los símbolos que reconocerá la aplicación para el cálculo de las operaciones: +# '+' para la suma. +# '-' para la resta. +# 'x' o '*' para la multiplicación. +# '/' o ':' para la división. +# '**' o 'exp' para la potencia. + + + +def limpiar_pantalla(): + """ + Limpia la consola según el sistema operativo. + """ + # TODO: El desarrollo de esta función está incompleto y con errores. + try: + if os.name == "nt": + os.system("cls") + else: + os.system("clear") + # Otra forma de expresar la misma instrucción sería la siguiente: + # if os.name = posix: + # os.system(clear) + # else: + # os.system(cls) + except Exception as e: + mostrar_error(f"No se ha podido llimpiar la pantalla: ERROR {e}") + + + +def pausa(): + """ + Pausa la ejecución del programa hasta que se pulse ENTER... "\nPresione ENTER para continuar..." + """ + input("\nPresione ENTER para continuar...") + # TODO: Desarrollar esta función según su documentación. + + +def mostrar_error(indice_error: int, msj_error = None): + """ + Muestra un mensaje de error en la consola. + + Args: + indice_error (int): Índice del mensaje de error en MENSAJES_ERROR. + msj_error (str, opcional): Texto adicional para personalizar el mensaje de error. + """ + # TODO: + # 1. Corrige el error que existe a la hora de acceder a los mensajes de error que están en la constante + # MENSAJES_ERROR. A los elementos de una tupla se accede igual que a los caracteres de una + # cadena de caracteres. + # 2. Completa el código de esta función para que controle específicamente las excepciones IndexError y + # muestre el mensaje: "\n*ERROR* Mensaje de error no definido.\n" + # 3. También se pide que se controle cualquier otra excepción que se pueda producir y muestre el mensaje: + # "\n*ERROR* Problemas al mostrar error!\n{e}\n" + # 4. En esta función los mensajes de error deben mostrarse con print. + try: + mensaje = MENSAJES_ERROR[indice_error] + if msj_error: + print(f"\n*ERROR* {mensaje.format(error=msj_error)}\n") + else: + print(f"\n*ERROR* {mensaje}\n") + except IndexError: + print("\n*ERROR* Mensaje de error no definido.\n") + except Exception as e: + print(f"\n*ERROR* Problemas al mostrar error!\n{e}\n") + + +def sumar(num1, num2): + """ + Realiza la operación suma entre num1 y num2. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + float: Resultado de la operación. + + """ + return num1 + num2 + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la suma de ambos. + + + +def restar(num1, num2): + """ + Realiza la operación resta entre num1 y num2. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + float: Resultado de la operación. + + """ + return num1 - num2 + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la resta de ambos. + + + +def es_resultado_negativo(num1: float, num2: float) -> bool: + """ + Realiza la operación especificada entre num1 y num2 para ver el signo. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + str: Resultado de la operación. + + """ + if num1 < 0 and num2 < 0: + signo = "positivo" + elif num1 >= 0 and num2 >= 0: + signo = "positivo" + else: + signo = "negativo" + return signo + + # TODO: Realizar el desarrollo completo de esta función teniendo en cuenta la documentación y completándola también. + # Debe pasar las pruebas unitarias. + # Se trata de una función que os puede venir bien para utilizarla tanto en la función multiplicar, como en dividir. + # Ya que va a determinar si la multiplicación o división entre dos números debería ser de signo negativo o no. + + + +def multiplicar(num1, num2): + """ + Realiza la multiplicación ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la multiplicación. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + signo = es_resultado_negativo(num1, num2) + resultado = 0 + num1 = abs(round(num1)) + num2 = abs(round(num2)) + for i in range(num1): + resultado += num2 + if signo == "positivo": + resultado = resultado + else: + resultado = -resultado + return resultado + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de multiplicación de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la multiplicación con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 * 3.33, deberá convertirse en 5 * 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 * -5 = 25 + # 6. OBLIGATORIO usar un bucle for. + # 7. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + + +def dividir(num1,num2): + """ + Realiza la división ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Dividendo. + num2 (float): Divisor. + + Returns: + int: Resultado de la división. + + Raises: + ZeroDivisionError: Si el divisor es cero. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + signo = es_resultado_negativo(num1, num2) + resultado = 0 + cuenta = True + num1 = abs(round(num1)) + num2 = abs(round(num2)) + while cuenta: + if num2 == 0: + raise ZeroDivisionError("Error: no es posible la división por 0! Introduzca otro valor diferente a 0...") + if num1 >= num2: + resultado += 1 + num1 -= num2 + else: + cuenta = False + + if signo == "positivo": + resultado = resultado + else: + resultado = -resultado + return resultado + + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de división de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la división con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 / 3.33, deberá convertirse en 5 / 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 / -5 = 1 + # 6. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + +def potencia(num1,num2): + """ + Realiza la operación potencia entre num1 y num2 . + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + int: Resultado de la operación. + + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función y su documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. PREMISAS a tener en cuenta: + # - Cualquier número elevado a 0 da como resultado 1. + # - Para simplificar esta función, vamos a suponer que un número elevado a un + # exponente negativo siempre dará 0 (aunque en realidad no es así matemáticamente) + # 4. Utiliza la función de multiplicar para realizar los cálculos que te + # harán falta en esta función (RECUERDA que no puedes usar directamente los operadores + # de Python para la multiplicación y división). + # 5. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + resultado = 0 + num1 = round(num1) + num2 = round(num2) + if num2 == 0: + resultado = 1 + elif num2 < 0: + resultado = 0 + elif num2 == 1: + resultado = num1 + + else: + for i in range(1,num2): + if i == 1: + resultado = multiplicar(num1, num1) + else: + resultado = multiplicar(num1, resultado) + return resultado + + + +def pedir_entrada(msj: str) -> str: + """ + Pide al usuario una entrada, elimina espacios por delante y por detrás y la convierte a minúsculas. + + Args: + msj (str): Mensaje para solicitar la entrada. + + Returns: + str: Entrada del usuario. + """ + # TODO: El desarrollo de esta función está incompleto, debéis terminarla teniendo en cuenta la documentación + return input(msj).strip().lower() + + +def calcular_operacion(num1: float, num2: float, operador: str) -> float: + """ + Realiza la operación especificada entre num1 y num2 dependiendo del valor del operador. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + float: Resultado de la operación. + + Raises: + ZeroDivisionError: Si el divisor es cero. + """ + # TODO: El desarrollo de esta función está incompleto... completadla teniendo en cuenta la documentación + # y que debe realizar las llamadas adecuadas a las funciones ya creadas para realizar los distintos + # cálculos... sumar, restar, multiplicar, dividir y potencia. + # IMPORTANTE: Si hacemos caso a la documentación de esta función, NO debéis capturar la excepción + # ZeroDivisionError aquí, sino que hay que dejadla que se propague a la función llamante, realizar_calculo(), + # dónde se os indica cómo realizar la gestión de estos errores. + if operador == "+": + resultado = sumar(num1, num2) + elif operador == "-": + resultado = restar(num1, num2) + elif operador == "x" or operador == "*": + resultado = multiplicar(num1, num2) + elif operador == "/" or operador == ":": + resultado = dividir(num1, num2) + elif operador == "**" or operador == "exp": + resultado = potencia(num1, num2) + return resultado + + + +def obtener_operaciones() -> str: + """ + Devuelve una cadena con la lista de operaciones disponibles en la calculadora. + + Returns: + (str): cadena de caracteres con la información de las operaciones disponibles. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + return( + "\nOperaciones disponibles:" + "\nce => Reiniciar resultado a 0" + "\ndecimales => Establecer decimales en resultado" + "\ncadena vacía + => Pregunta si desea salir" + "\ncalculo => Iniciar cálculo secuencial" + "\n + => Suma" + "\n - => Resta" + "\n o * => Multiplicación" + "\n / o : => División" + "\n ** o exp => Potencia" + "\n cancelar => vovler sin actualizar resultado de la calculadora" + "\n cadena vacía + => volver actualizando resultado de la calculadora" + ) + + + +def realizar_calculo(decimales, resultado_almacenado): + """ + Realiza una secuencia de cálculos solicitando números y operadores al usuario. + + Args: + decimales (int): Número de decimales para el resultado. + resultado_almacenado (float): Valor almacenado en la calculadora. + + Returns: + float: Resultado final del cálculo o None si se cancela. + + Note: + * Dentro de esta función el usuario puede realizar cálculos secuenciales, es decir, + comenzará introduciendo un número, después un operador, y otro número... a partir + de aquí sobre el resultado acumulado, introducirá operador y número para seguir + realizando cálculos (ver ejemplos en README.md de la tarea en el repositorio de GitHub). + * El usuario es guiado para introducir números y operadores secuencialmente + para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el + resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado + de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el + resultado almacenado de la calculadora. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + + operador = None + resultado = None + realizando_calculos = True + + print("\n## Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo ##\n") + while realizando_calculos: + entrada = pedir_entrada(f"\t (Cálculo = {resultado}) >> ") + + if entrada == "cancelar": + realizando_calculos = False + + + elif entrada == "": + realizando_calculos = False + + + elif entrada in OPERADORES: + operador = entrada + + else: + # TODO: este código funciona cuando solucionéis que reconozca las variables resultado_almacenado y decimales. + # Pero no gestiona los posibles tipos de Excepciones que se pueden producir: + # - ValueError que debe mostrar el error que está en la posición 2 de MENSAJES_ERROR. + # - ZeroDivisionError que debe mostrar el error que está en la posición 5 de MENSAJES_ERROR. + # - Exception que debe mostrar el error que está en la posición 6 de MENSAJES_ERROR. + if entrada == "resultado": + entrada = resultado_almacenado + + try: + numero = float(entrada) + + if operador: + if resultado is None: + resultado = 0 + resultado = round(calcular_operacion(resultado, numero, operador), decimales) + operador = None + + elif resultado is None: + resultado = numero + + else: + mostrar_error(3) + except ValueError: + mostrar_error(2) + except ZeroDivisionError: + mostrar_error(5) + except Exception as e: + mostrar_error(6, str(e)) + return resultado + + + + +def main(): + """ + Función principal de la calculadora. Gestiona la entrada del usuario y coordina las operaciones. + + Note: + El flujo del programa es el siguiente: + + 1. Inicia la calculadora mostrando el resultado almacenado por defecto (0.00). + + 2. El usuario ingresa un comando, que puede ser: + - "lista" para ver todas las operaciones disponibles. + - "ce" para reiniciar el resultado almacenado a 0. + - "decimales " para establecer el número de decimales mostrados en el resultado. + - "calculo" para iniciar una secuencia de cálculo paso a paso. + - Una entrada vacía y pulsa la tecla para salir de la calculadora. + + 3. Según el comando ingresado: + - El programa realiza la operación o ejecuta la acción indicada. + - Al ingresar "calculo": + * El usuario es guiado para introducir números y operadores secuencialmente para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el resultado almacenado de la calculadora. + + 4. La calculadora sigue ejecutándose hasta que el usuario confirma la salida al ingresar una entrada vacía y pulsar . + + 5. Finalmente, se limpia la pantalla, el programa se despide con el mensaje "\n\nBye, bye...\n\n" y termina. + """ + # TODO: Corrige los errores y haz que el main funcione correctamente... + entrada = None + desea_salir = False + decimales = 2 + resultado_almacenado = 0.00 + + while not desea_salir: + + entrada = pedir_entrada(f"Operación (RES => {resultado_almacenado}) >> ") + + if entrada == "": + salir= pedir_entrada("¿Desea salir de la calculadora? (s/n) ") + if salir == "s" or salir == "si": + desea_salir = True + + elif entrada == "lista": + print(obtener_operaciones()) + + elif entrada == "ce": + resultado_almacenado = 0.0 + + + elif entrada.startswith("decimales"): + # Extraemos las posiciones decimales y las convertimos a un valor entero + try: + decimales = int(entrada.split()[1]) + round(resultado_almacenado, decimales) + print(f"Decimales configurados a {decimales}.") + except (IndexError, ValueError): + mostrar_error(1) + + elif entrada == "calculo": + resultado_almacenado = realizar_calculo(decimales, resultado_almacenado) + + else: + mostrar_error + limpiar_pantalla() + print("\n\nBye, bye...\n\n") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/daw1b_calculadora/alfonso_calculadora_alumnos_bonus.py b/daw1b_calculadora/alfonso_calculadora_alumnos_bonus.py new file mode 100644 index 0000000..3613633 --- /dev/null +++ b/daw1b_calculadora/alfonso_calculadora_alumnos_bonus.py @@ -0,0 +1,505 @@ +# TODO: ATENCIÓN!!! +# 1. Importar los paquetes necesarios +# 2. Usar la función mostrar_error para imprimir los errores por consola. +# 3. Los comentarios TODO os ayudan a resolver cada apartado de esta prueba. +# 4. CADA función SOLO puede tener una instrucción return. +# 5. En test_calculadora_alumnos.py crear el test unitario para la función es_resultado_negativo y hacer que todos los test unitarios se cumplan. +import os + + +# Mensajes de error predefinidos +MENSAJES_ERROR = ( + "Problemas al intentar limpiar la pantalla {error}", + "Error al configurar los decimales. Formato: decimales .", + "Entrada no válida. Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo.", + "Error: Introduzca un operador antes de otro número.", + "Comando no reconocido. Escriba 'lista' para ver las operaciones disponibles.", + "Error: no es posible la división por 0! Introduzca otro valor diferente a 0...", + "Se produjo un error: {error}" +) + +# Operadores soportados por la calculadora +OPERADORES = ["+", "-", "x", "*", "/", ":", "**", "exp"] +# TODO: Ayuda: incluye en esta constante los símbolos que reconocerá la aplicación para el cálculo de las operaciones: +# '+' para la suma. +# '-' para la resta. +# 'x' o '*' para la multiplicación. +# '/' o ':' para la división. +# '**' o 'exp' para la potencia. + + + +def limpiar_pantalla(): + """ + Limpia la consola según el sistema operativo. + """ + # TODO: El desarrollo de esta función está incompleto y con errores. + try: + if os.name == "nt": + os.system("cls") + else: + os.system("clear") + # Otra forma de expresar la misma instrucción sería la siguiente: + # if os.name = posix: + # os.system(clear) + # else: + # os.system(cls) + except Exception as e: + mostrar_error(f"No se ha podido llimpiar la pantalla: ERROR {e}") + + + +def pausa(): + """ + Pausa la ejecución del programa hasta que se pulse ENTER... "\nPresione ENTER para continuar..." + """ + input("\nPresione ENTER para continuar...") + # TODO: Desarrollar esta función según su documentación. + + +def mostrar_error(indice_error: int, msj_error = None): + """ + Muestra un mensaje de error en la consola. + + Args: + indice_error (int): Índice del mensaje de error en MENSAJES_ERROR. + msj_error (str, opcional): Texto adicional para personalizar el mensaje de error. + """ + # TODO: + # 1. Corrige el error que existe a la hora de acceder a los mensajes de error que están en la constante + # MENSAJES_ERROR. A los elementos de una tupla se accede igual que a los caracteres de una + # cadena de caracteres. + # 2. Completa el código de esta función para que controle específicamente las excepciones IndexError y + # muestre el mensaje: "\n*ERROR* Mensaje de error no definido.\n" + # 3. También se pide que se controle cualquier otra excepción que se pueda producir y muestre el mensaje: + # "\n*ERROR* Problemas al mostrar error!\n{e}\n" + # 4. En esta función los mensajes de error deben mostrarse con print. + try: + mensaje = MENSAJES_ERROR[indice_error] + if msj_error: + print(f"\n*ERROR* {mensaje.format(error=msj_error)}\n") + else: + print(f"\n*ERROR* {mensaje}\n") + except IndexError: + print("\n*ERROR* Mensaje de error no definido.\n") + except Exception as e: + print(f"\n*ERROR* Problemas al mostrar error!\n{e}\n") + + +def sumar(num1, num2): + """ + Realiza la operación suma entre num1 y num2. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + float: Resultado de la operación. + + """ + return num1 + num2 + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la suma de ambos. + + + +def restar(num1, num2): + """ + Realiza la operación resta entre num1 y num2. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + float: Resultado de la operación. + + """ + return num1 - num2 + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la resta de ambos. + + + +def es_resultado_negativo(num1: float, num2: float) -> bool: + """ + Realiza la operación especificada entre num1 y num2 para ver el signo. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + str: Resultado de la operación. + + """ + if num1 < 0 and num2 < 0: + signo = "positivo" + elif num1 >= 0 and num2 >= 0: + signo = "positivo" + else: + signo = "negativo" + return signo + + """Determina si el resultado de una operación entre num1 y num2 debe ser negativo.""" + # TODO: Realizar el desarrollo completo de esta función teniendo en cuenta la documentación y completándola también. + # Debe pasar las pruebas unitarias. + # Se trata de una función que os puede venir bien para utilizarla tanto en la función multiplicar, como en dividir. + # Ya que va a determinar si la multiplicación o división entre dos números debería ser de signo negativo o no. + + + +def multiplicar(num1, num2): + """ + Realiza la multiplicación ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la multiplicación. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + signo = es_resultado_negativo(num1, num2) + resultado = 0 + num1 = abs(round(num1)) + num2 = abs(round(num2)) + for i in range(num1): + resultado += num2 + if signo == "positivo": + resultado = resultado + else: + resultado = -resultado + return resultado + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de multiplicación de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la multiplicación con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 * 3.33, deberá convertirse en 5 * 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 * -5 = 25 + # 6. OBLIGATORIO usar un bucle for. + # 7. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + + +def dividir(num1,num2): + """ + Realiza la división ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Dividendo. + num2 (float): Divisor. + + Returns: + int: Resultado de la división. + + Raises: + ZeroDivisionError: Si el divisor es cero. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + signo = es_resultado_negativo(num1, num2) + resultado = 0 + cuenta = True + num1 = abs(round(num1)) + num2 = abs(round(num2)) + while cuenta: + if num1 >= num2: + resultado += 1 + num1 -= num2 + else: + cuenta = False + + if signo == "positivo": + resultado = resultado + else: + resultado = -resultado + return resultado + + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de división de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la división con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 / 3.33, deberá convertirse en 5 / 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 / -5 = 1 + # 6. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + +def potencia(num1,num2): + """ + Realiza la operación potencia entre num1 y num2 . + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + int: Resultado de la operación. + + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función y su documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. PREMISAS a tener en cuenta: + # - Cualquier número elevado a 0 da como resultado 1. + # - Para simplificar esta función, vamos a suponer que un número elevado a un + # exponente negativo siempre dará 0 (aunque en realidad no es así matemáticamente) + # 4. Utiliza la función de multiplicar para realizar los cálculos que te + # harán falta en esta función (RECUERDA que no puedes usar directamente los operadores + # de Python para la multiplicación y división). + # 5. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + resultado = 0 + num1 = abs(round(num1)) + num2 = abs(round(num2)) + if num2 == 0: + resultado = 1 + elif num2 < 0: + resultado = 0 + elif num2 == 1: + resultado = num1 + else: + for i in range(1,num2): + if i == 1: + resultado = multiplicar(num1, num1) + else: + resultado = multiplicar(num1, resultado) + return resultado + + + +def pedir_entrada(msj: str) -> str: + """ + Pide al usuario una entrada, elimina espacios por delante y por detrás y la convierte a minúsculas. + + Args: + msj (str): Mensaje para solicitar la entrada. + + Returns: + str: Entrada del usuario. + """ + # TODO: El desarrollo de esta función está incompleto, debéis terminarla teniendo en cuenta la documentación + return input(msj).strip().lower() + + +def calcular_operacion(num1: float, num2: float, operador: str) -> float: + """ + Realiza la operación especificada entre num1 y num2 dependiendo del valor del operador. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + float: Resultado de la operación. + + Raises: + ZeroDivisionError: Si el divisor es cero. + """ + # TODO: El desarrollo de esta función está incompleto... completadla teniendo en cuenta la documentación + # y que debe realizar las llamadas adecuadas a las funciones ya creadas para realizar los distintos + # cálculos... sumar, restar, multiplicar, dividir y potencia. + # IMPORTANTE: Si hacemos caso a la documentación de esta función, NO debéis capturar la excepción + # ZeroDivisionError aquí, sino que hay que dejadla que se propague a la función llamante, realizar_calculo(), + # dónde se os indica cómo realizar la gestión de estos errores. + if operador == "+": + resultado = sumar(num1, num2) + elif operador == "-": + resultado = restar(num1, num2) + elif operador == "x" or operador == "*": + resultado = multiplicar(num1, num2) + elif operador == "/" or operador == ":": + resultado = dividir(num1, num2) + elif operador == "**" or operador == "exp": + resultado = potencia(num1, num2) + return resultado + + + +def obtener_operaciones() -> str: + """ + Devuelve una cadena con la lista de operaciones disponibles en la calculadora. + + Returns: + (str): cadena de caracteres con la información de las operaciones disponibles. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + return( + "\n\nOperaciones disponibles:" + "\n+ => Suma" + "\n- => Resta" + "\nx o * => Multiplicación" + "\n/ o : => División" + "\n** exp => Potencia" + "\ncancelar => vovler sin actualizar el resultado de la calculadora" + "\ncadena vacía + => volver al menú actualizando el resultado de la calculadora\n\n" + ) + + + +def realizar_calculo(decimales, resultado_almacenado): + """ + Realiza una secuencia de cálculos solicitando números y operadores al usuario. + + Args: + decimales (int): Número de decimales para el resultado. + resultado_almacenado (float): Valor almacenado en la calculadora. + + Returns: + float: Resultado final del cálculo o None si se cancela. + + Note: + * Dentro de esta función el usuario puede realizar cálculos secuenciales, es decir, + comenzará introduciendo un número, después un operador, y otro número... a partir + de aquí sobre el resultado acumulado, introducirá operador y número para seguir + realizando cálculos (ver ejemplos en README.md de la tarea en el repositorio de GitHub). + * El usuario es guiado para introducir números y operadores secuencialmente + para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el + resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado + de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el + resultado almacenado de la calculadora. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + + operador = None + resultado = None + realizando_calculos = True + print("\n## Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo ##\n") + while realizando_calculos: + entrada = pedir_entrada(f"\t (Cálculo = {resultado}) >> ") + + if entrada == "cancelar": + realizando_calculos = False + + + elif entrada == "": + realizando_calculos = False + + + elif entrada in OPERADORES: + operador = entrada + + else: + # TODO: este código funciona cuando solucionéis que reconozca las variables resultado_almacenado y decimales. + # Pero no gestiona los posibles tipos de Excepciones que se pueden producir: + # - ValueError que debe mostrar el error que está en la posición 2 de MENSAJES_ERROR. + # - ZeroDivisionError que debe mostrar el error que está en la posición 5 de MENSAJES_ERROR. + # - Exception que debe mostrar el error que está en la posición 6 de MENSAJES_ERROR. + if entrada == "resultado": + entrada = resultado_almacenado + + try: + numero = float(entrada) + + if operador: + if resultado is None: + resultado = 0 + resultado = round(calcular_operacion(resultado, numero, operador), decimales) + operador = None + + elif resultado is None: + resultado = numero + + else: + mostrar_error(3) + except ValueError: + mostrar_error(2) + except ZeroDivisionError: + mostrar_error(5) + except Exception as e: + mostrar_error(6, str(e)) + return resultado + +def titulos(): + return( + "Menú" + "\n1. Realizar un cálculo secuencial." + "\n2. Lista de operaciones disponibles para el cálculo." + "\n3. Reiniciar resultado (CE)." + "\n4. Configurar número de decimales." + "\n5. Salir. \n\n" + ) + + + +def main(): + """ + Función principal de la calculadora. Gestiona la entrada del usuario y coordina las operaciones. + + Note: + El flujo del programa es el siguiente: + + 1. Inicia la calculadora mostrando el resultado almacenado por defecto (0.00). + + 2. El usuario ingresa un comando, que puede ser: + - "lista" para ver todas las operaciones disponibles. + - "ce" para reiniciar el resultado almacenado a 0. + - "decimales " para establecer el número de decimales mostrados en el resultado. + - "calculo" para iniciar una secuencia de cálculo paso a paso. + - Una entrada vacía y pulsa la tecla para salir de la calculadora. + + 3. Según el comando ingresado: + - El programa realiza la operación o ejecuta la acción indicada. + - Al ingresar "calculo": + * El usuario es guiado para introducir números y operadores secuencialmente para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el resultado almacenado de la calculadora. + + 4. La calculadora sigue ejecutándose hasta que el usuario confirma la salida al ingresar una entrada vacía y pulsar . + + 5. Finalmente, se limpia la pantalla, el programa se despide con el mensaje "\n\nBye, bye...\n\n" y termina. + """ + # TODO: Corrige los errores y haz que el main funcione correctamente... + entrada = None + desea_salir = False + decimales = 2 + resultado_almacenado = 0.00 + while not desea_salir: + entrada = int(input(f"{titulos()}\n =>")) + + if entrada == 5: + salir= pedir_entrada("¿Desea salir de la calculadora? (s/n) ") + if salir == "s" or salir == "si": + desea_salir = True + + elif entrada == 2: + print(obtener_operaciones()) + + elif entrada == 3: + resultado_almacenado = 0.0 + + + elif entrada== 4: + # Extraemos las posiciones decimales y las convertimos a un valor entero + try: + decimales = int(input("Introduzca la cantidad de decimales: ")) + round(resultado_almacenado, decimales) + print(f"Decimales configurados a {decimales}.") + except (IndexError, ValueError): + mostrar_error(1) + + elif entrada == 1: + resultado_almacenado = realizar_calculo(decimales, resultado_almacenado) + + else: + mostrar_error + limpiar_pantalla() + print("\n\nBye, bye...\n\n") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/daw1b_calculadora/angel_calculadora_alumnos.py b/daw1b_calculadora/angel_calculadora_alumnos.py new file mode 100644 index 0000000..2a569f9 --- /dev/null +++ b/daw1b_calculadora/angel_calculadora_alumnos.py @@ -0,0 +1,428 @@ +import os + +# TODO: ATENCIÓN!!! +# 1. Importar los paquetes necesarios +# 2. Usar la función mostrar_error para imprimir los errores por consola. +# 3. Los comentarios TODO os ayudan a resolver cada apartado de esta prueba. +# 4. CADA función SOLO puede tener una instrucción return. +# 5. En test_calculadora_alumnos.py crear el test unitario para la función es_resultado_negativo y hacer que todos los test unitarios se cumplan. + +# Mensajes de error predefinidos +MENSAJES_ERROR = ( + "Problemas al intentar limpiar la pantalla {error}", + "Error al configurar los decimales. Formato: decimales .", + "Entrada no válida. Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo.", + "Error: Introduzca un operador antes de otro número.", + "Comando no reconocido. Escriba 'lista' para ver las operaciones disponibles.", + "Error: no es posible la división por 0! Introduzca otro valor diferente a 0...", + "Se produjo un error: {error}" +) + +# Operadores soportados por la calculadora +OPERADORES = {"+", "-", "x", "*", "/", ":", "**", "exp"} +# TODO: Ayuda: incluye en esta constante los símbolos que reconocerá la aplicación para el cálculo de las operaciones: +# '+' para la suma. +# '-' para la resta. +# 'x' o '*' para la multiplicación. +# '/' o ':' para la división. +# '**' o 'exp' para la potencia. + + +def limpiar_pantalla(): + """Limpia la consola según el sistema operativo.""" + # TODO: El desarrollo de esta función está incompleto y con errores. + # Otra forma de expresar la misma instrucción sería la siguiente: + # if os.name = posix: + # os.system(clear) + # else: + # os.system(cls) + + try: + os.system('clear' if os.name == 'posix' else 'cls') + except Exception as e: + mostrar_error(0, str(e)) + +def pausa(): + + """Pausa la ejecución del programa hasta que se pulse ENTER...""" + # TODO: Desarrollar esta función según su documentación. + input("\nPresione ENTER para continuar...") + +def mostrar_error(indice_error: int, msj_error=None): + + """ + Muestra un mensaje de error en la consola. + + Args: + indice_error (int): Índice del mensaje de error en MENSAJES_ERROR. + msj_error (str, opcional): Texto adicional para personalizar el mensaje de error. + """ + # TODO: + # 1. Corrige el error que existe a la hora de acceder a los mensajes de error que están en la constante + # MENSAJES_ERROR. A los elementos de una tupla se accede igual que a los caracteres de una + # cadena de caracteres. + # 2. Completa el código de esta función para que controle específicamente las excepciones IndexError y + # muestre el mensaje: "\n*ERROR* Mensaje de error no definido.\n" + # 3. También se pide que se controle cualquier otra excepción que se pueda producir y muestre el mensaje: + # "\n*ERROR* Problemas al mostrar error!\n{e}\n" + # 4. En esta función los mensajes de error deben mostrarse con print. + + try: + if msj_error: + print(f"\n*ERROR* {MENSAJES_ERROR[indice_error].format(error=msj_error)}\n") + else: + print(f"\n*ERROR* {MENSAJES_ERROR[indice_error]}\n") + except IndexError: + print("\n*ERROR* Mensaje de error no definido.\n") + except Exception as e: + print(f"\n*ERROR* Problemas al mostrar error!\n{e}\n") + +def sumar(num1, num2): + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la suma de ambos. + return num1 + num2 + +def restar(num1, num2): + + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la resta de ambos. + + return num1 - num2 + +def es_resultado_negativo(num1, num2): + + """Determina si el resultado de una operación entre num1 y num2 debe ser negativo.""" + # TODO: Realizar el desarrollo completo de esta función teniendo en cuenta la documentación y completándola también. + # Debe pasar las pruebas unitarias. + # Se trata de una función que os puede venir bien para utilizarla tanto en la función multiplicar, como en dividir. + # Ya que va a determinar si la multiplicación o división entre dos números debería ser de signo negativo o no. + + return (num1 < 0) != (num2 < 0) + +def multiplicar(num1, num2): + """ + Realiza la multiplicación ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la multiplicación. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de multiplicación de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la multiplicación con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 * 3.33, deberá convertirse en 5 * 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 * -5 = 25 + # 6. OBLIGATORIO usar un bucle for. + # 7. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + num1, num2 = round(num1), round(num2) + resultado = 0 + for _ in range(abs(num2)): + resultado += num1 + return resultado if num2 >= 0 else -resultado + + #Aquí se puede observar como sin usar *, hemos conseguido realizar una multiplicación. Redondeamos primero num1 y num2 para, por ejemplo + +def dividir(num1, num2): + + """ + Realiza la división ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Dividendo. + num2 (float): Divisor. + + Returns: + int: Resultado de la división. + + Raises: + ZeroDivisionError: Si el divisor es cero. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de división de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la división con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 / 3.33, deberá convertirse en 5 / 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 / -5 = 1 + # 6. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + if num2 == 0: + raise ZeroDivisionError + num1, num2 = round(num1), round(num2) + resultado = 0 + temp = abs(num1) + while temp >= abs(num2): + temp -= abs(num2) + resultado += 1 + return resultado if es_resultado_negativo(num1, num2) else -resultado + +def potencia(num1, exp): + + # TODO: + # 1. Realizar el desarrollo completo de esta función y su documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. PREMISAS a tener en cuenta: + # - Cualquier número elevado a 0 da como resultado 1. + # - Para simplificar esta función, vamos a suponer que un número elevado a un + # exponente negativo siempre dará 0 (aunque en realidad no es así matemáticamente) + # 4. Utiliza la función de multiplicar para realizar los cálculos que te + # harán falta en esta función (RECUERDA que no puedes usar directamente los operadores + # de Python para la multiplicación y división). + # 5. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + if exp == 0: + return 1 + if exp < 0: + return 0 + + for _ in range (exp): + resultado = resultado**exp + return resultado + +def pedir_entrada(msj): + + """ + Pide al usuario una entrada, elimina espacios por delante y por detrás y la convierte a minúsculas. + + Args: + msj (str): Mensaje para solicitar la entrada. + + Returns: + str: Entrada del usuario. + """ + # TODO: El desarrollo de esta función está incompleto, debéis terminarla teniendo en cuenta la documentación + + return input(msj).strip().lower() + +def obtener_operaciones(): + """ + Devuelve una cadena con la lista de operaciones disponibles en la calculadora. + + Returns: + (str): cadena de caracteres con la información de las operaciones disponibles. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + """ + Operaciones disponibles: + ce => Reiniciar resultado a 0 + decimales => Establecer decimales en resultado + cadena vacía + => Pregunta si desea salir + calculo => Iniciar cálculo secuencial + + => Suma + - => Resta + x o * => Multiplicación + / o : => División + ** o exp => Potencia + cancelar => vovler sin actualizar resultado de la calculadora + cadena vacía + => volver actualizando resultado de la calculadora + """ + return """ +Operaciones disponibles: + ce => Reiniciar resultado a 0 + decimales => Establecer decimales en resultado + cadena vacía + => Pregunta si desea salir + calculo => Iniciar cálculo secuencial + + => Suma + - => Resta + x o * => Multiplicación + / o : => División + ** o exp => Potencia + cancelar => volver sin actualizar resultado de la calculadora + cadena vacía + => volver actualizando resultado de la calculadora +""" + +def calcular_operacion(num1, num2, operador): + """ + Realiza la operación especificada entre num1 y num2 dependiendo del valor del operador. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + float: Resultado de la operación. + + Raises: + ZeroDivisionError: Si el divisor es cero. + """ + # TODO: El desarrollo de esta función está incompleto... completadla teniendo en cuenta la documentación + # y que debe realizar las llamadas adecuadas a las funciones ya creadas para realizar los distintos + # cálculos... sumar, restar, multiplicar, dividir y potencia. + # IMPORTANTE: Si hacemos caso a la documentación de esta función, NO debéis capturar la excepción + # ZeroDivisionError aquí, sino que hay que dejadla que se propague a la función llamante, realizar_calculo(), + # dónde se os indica cómo realizar la gestión de estos errores. + + if operador == "+": + return sumar(num1, num2) + elif operador == "-": + return restar(num1, num2) + elif operador in {"*", "x"}: + return multiplicar(num1, num2) + elif operador in {"/", ":"}: + return dividir(num1, num2) + elif operador in {"**", "exp"}: + return potencia(num1, num2) + else: + mostrar_error(4) + return None + +def realizar_calculo(decimales, resultado_almacenado): + """ + Realiza una secuencia de cálculos solicitando números y operadores al usuario. + + Args: + decimales (int): Número de decimales para el resultado. + resultado_almacenado (float): Valor almacenado en la calculadora. + + Returns: + float: Resultado final del cálculo o None si se cancela. + + Note: + * Dentro de esta función el usuario puede realizar cálculos secuenciales, es decir, + comenzará introduciendo un número, después un operador, y otro número... a partir + de aquí sobre el resultado acumulado, introducirá operador y número para seguir + realizando cálculos (ver ejemplos en README.md de la tarea en el repositorio de GitHub). + * El usuario es guiado para introducir números y operadores secuencialmente + para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el + resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado + de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el + resultado almacenado de la calculadora. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + + operador = None + resultado = None + realizando_calculos = True + print("\n## Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo ##\n") + + while realizando_calculos: + entrada = pedir_entrada("(Cálculo = {}) >> ".format(resultado if resultado else 0)) + + if entrada == "cancelar": + print("\nSecuencia cancelada. Resultado almacenado sin cambios.\n") + pausa() + return resultado_almacenado + + elif entrada == "": + print("\nResultado actualizado en la calculadora.\n") + pausa() + return resultado + + elif entrada in OPERADORES: + operador = entrada + + else: # TODO: este código funciona cuando solucionéis que reconozca las variables resultado_almacenado y decimales. + # Pero no gestiona los posibles tipos de Excepciones que se pueden producir: + # - ValueError que debe mostrar el error que está en la posición 2 de MENSAJES_ERROR. + # - ZeroDivisionError que debe mostrar el error que está en la posición 5 de MENSAJES_ERROR. + # - Exception que debe mostrar el error que está en la posición 6 de MENSAJES_ERROR. + + if entrada == "resultado": + entrada = resultado_almacenado + + try: + numero = float(entrada) + if operador: + if resultado is None: + resultado = 0 + resultado = round(calcular_operacion(resultado, numero, operador), decimales) + operador = None + else: + resultado = numero + except ValueError: + mostrar_error(2) + except ZeroDivisionError: + mostrar_error(5) + except Exception as e: + mostrar_error(6, str(e)) + +def main(): + + """ + Función principal de la calculadora. Gestiona la entrada del usuario y coordina las operaciones. + + Note: + El flujo del programa es el siguiente: + + 1. Inicia la calculadora mostrando el resultado almacenado por defecto (0.00). + + 2. El usuario ingresa un comando, que puede ser: + - "lista" para ver todas las operaciones disponibles. + - "ce" para reiniciar el resultado almacenado a 0. + - "decimales " para establecer el número de decimales mostrados en el resultado. + - "calculo" para iniciar una secuencia de cálculo paso a paso. + - Una entrada vacía y pulsa la tecla para salir de la calculadora. + + 3. Según el comando ingresado: + - El programa realiza la operación o ejecuta la acción indicada. + - Al ingresar "calculo": + * El usuario es guiado para introducir números y operadores secuencialmente para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el resultado almacenado de la calculadora. + + 4. La calculadora sigue ejecutándose hasta que el usuario confirma la salida al ingresar una entrada vacía y pulsar . + + 5. Finalmente, se limpia la pantalla, el programa se despide con el mensaje "\n\nBye, bye...\n\n" y termina. + """ + # TODO: Corrige los errores y haz que el main funcione correctamente... + + + print("### CALCULADORA ###\n -----------\n") + decimales = 2 + resultado = 0.0 + desea_salir = False + + while not desea_salir: + entrada = pedir_entrada("Operación (RES => {:.{}f}) >> ".format(resultado, decimales)) + + if entrada == "": + salida = pedir_entrada("¿Desea salir de la calculadora? (s/n) ") + if salida == "s": + limpiar_pantalla() + print("\n\nBye, bye...\n\n") + desea_salir = True + else: + limpiar_pantalla() + + elif entrada == "lista": + print(obtener_operaciones()) + pausa() + + elif entrada == "ce": + resultado = 0.0 + print("Resultado reiniciado a 0.") + pausa() + + elif entrada.startswith("decimales"): + try: + decimales = int(entrada.split()[1]) + print(f"Decimales configurados a {decimales}.") + pausa() + except (IndexError, ValueError): + mostrar_error(1) + + elif entrada == "calculo": + resultado = realizar_calculo(decimales, resultado) + + else: + mostrar_error(4) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/daw1b_calculadora/antonio_calculadora_alumnos.py b/daw1b_calculadora/antonio_calculadora_alumnos.py new file mode 100644 index 0000000..7b25ea2 --- /dev/null +++ b/daw1b_calculadora/antonio_calculadora_alumnos.py @@ -0,0 +1,401 @@ +# TODO: ATENCIÓN!!! +# 1. Importar los paquetes necesarios +# 2. Usar la función mostrar_error para imprimir los errores por consola. +# 3. Los comentarios TODO os ayudan a resolver cada apartado de esta prueba. +# 4. CADA función SOLO puede tener una instrucción return. +# 5. En test_calculadora_alumnos.py crear el test unitario para la función es_resultado_negativo y hacer que todos los test unitarios se cumplan. + +import os +import time + +# Mensajes de error predefinidos +MENSAJES_ERROR = ( + "Problemas al intentar limpiar la pantalla {error}", + "Error al configurar los decimales. Formato: decimales .", + "Entrada no válida. Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo.", + "Error: Introduzca un operador antes de otro número.", + "Comando no reconocido. Escriba 'lista' para ver las operaciones disponibles.", + "Error: no es posible la división por 0! Introduzca otro valor diferente a 0...", + "Se produjo un error: {error}" +) + +# Operadores soportados por la calculadora +OPERADORES = ['+', '-', 'x', '/', '**', 's'] +# TODO: Ayuda: incluye en esta constante los símbolos que reconocerá la aplicación para el cálculo de las operaciones: +# '+' para la suma. +# '-' para la resta. +# 'x' o '*' para la multiplicación. +# '/' o ':' para la división. +# '**' o 'exp' para la potencia. + + + +def limpiar_pantalla(): + """ + Limpia la consola según el sistema operativo. + """ + # TODO: El desarrollo de esta función está incompleto y con errores. + try: + os.system("clear" if os.name == "posix" else "cls") + # Otra forma de expresar la misma instrucción sería la siguiente: + # if os.name = posix: + # os.system(clear) + # else: + # os.system(cls) + except Exception as e: + mostrar_error(f"Problemas al intentar limpiar la pantalla: {e}") + + + +def pausa(tecla_enter = True): + """ + Pausa la ejecución del programa hasta que se pulse ENTER... "\nPresione ENTER para continuar..." + """ + # TODO: Desarrollar esta función según su documentación. + if tecla_enter: + input("\nPresione ENTER para continuar...") + + +def mostrar_error(indice_error: int, msj_error = None): + """ + Muestra un mensaje de error en la consola. + + Args: + indice_error (int): Índice del mensaje de error en MENSAJES_ERROR. + msj_error (str, opcional): Texto adicional para personalizar el mensaje de error. + """ + # TODO: + # 1. Corrige el error que existe a la hora de acceder a los mensajes de error que están en la constante + # MENSAJES_ERROR. A los elementos de una tupla se accede igual que a los caracteres de una + # cadena de caracteres. + # 2. Completa el código de esta función para que controle específicamente las excepciones IndexError y + # muestre el mensaje: "\n*ERROR* Mensaje de error no definido.\n" + # 3. También se pide que se controle cualquier otra excepción que se pueda producir y muestre el mensaje: + # "\n*ERROR* Problemas al mostrar error!\n{e}\n" + # 4. En esta función los mensajes de error deben mostrarse con print. + if msj_error != None: + print(f"\n*ERROR* {MENSAJES_ERROR.format(error = msj_error)}\n") + else: + print(f"\n*ERROR* {MENSAJES_ERROR}\n") + + +def sumar(num1: float, num2: float): + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la suma de ambos. + return num1 + num2 + + + + +def restar(num1: float, num2: float): + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la resta de ambos. + return num1 - num2 + + + +def es_resultado_negativo(num1: float, num2: float) -> bool: + """Determina si el resultado de una operación entre num1 y num2 debe ser negativo.""" + # TODO: Realizar el desarrollo completo de esta función teniendo en cuenta la documentación y completándola también. + # Debe pasar las pruebas unitarias. + # Se trata de una función que os puede venir bien para utilizarla tanto en la función multiplicar, como en dividir. + # Ya que va a determinar si la multiplicación o división entre dos números debería ser de signo negativo o no. + + + +def multiplicar(num1: float, num2: float): + """ + Realiza la multiplicación ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la multiplicación. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de multiplicación de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la multiplicación con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 * 3.33, deberá convertirse en 5 * 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 * -5 = 25 + # 6. OBLIGATORIO usar un bucle for. + # 7. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + num1 = round(num1) + num2 = round(num2) + producto = 0 + + for i in range((num2)): + producto += (num1) + + if es_resultado_negativo(num1, num2): + producto = -producto + + return producto + + + +def dividir(num1, num2): + """ + Realiza la división ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Dividendo. + num2 (float): Divisor. + + Returns: + int: Resultado de la división. + + Raises: + ZeroDivisionError: Si el divisor es cero. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de división de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la división con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 / 3.33, deberá convertirse en 5 / 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 / -5 = 1 + # 6. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + if num2 == 0: + raise ZeroDivisionError("No se puede dividir por 0.") + + num1 = round(num1) + num2 = round(num2) + cociente = 0 + while num1 >= num2: + num1 -= num2 + cociente += 1 + + if es_resultado_negativo(num1, num2): + cociente = -cociente + + return cociente + + +def potencia(): + # TODO: + # 1. Realizar el desarrollo completo de esta función y su documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. PREMISAS a tener en cuenta: + # - Cualquier número elevado a 0 da como resultado 1. + # - Para simplificar esta función, vamos a suponer que un número elevado a un + # exponente negativo siempre dará 0 (aunque en realidad no es así matemáticamente) + # 4. Utiliza la función de multiplicar para realizar los cálculos que te + # harán falta en esta función (RECUERDA que no puedes usar directamente los operadores + # de Python para la multiplicación y división). + # 5. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + +def pedir_entrada(msj: str) -> str: + """ + Pide al usuario una entrada, elimina espacios por delante y por detrás y la convierte a minúsculas. + + Args: + msj (str): Mensaje para solicitar la entrada. + + Returns: + str: Entrada del usuario. + """ + # TODO: El desarrollo de esta función está incompleto, debéis terminarla teniendo en cuenta la documentación + return input(msj) + + +def calcular_operacion(num1: float, num2: float, operador: str) -> float: + """ + Realiza la operación especificada entre num1 y num2 dependiendo del valor del operador. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + float: Resultado de la operación. + + Raises: + ZeroDivisionError: Si el divisor es cero. + """ + # TODO: El desarrollo de esta función está incompleto... completadla teniendo en cuenta la documentación + # y que debe realizar las llamadas adecuadas a las funciones ya creadas para realizar los distintos + # cálculos... sumar, restar, multiplicar, dividir y potencia. + # IMPORTANTE: Si hacemos caso a la documentación de esta función, NO debéis capturar la excepción + # ZeroDivisionError aquí, sino que hay que dejadla que se propague a la función llamante, realizar_calculo(), + # dónde se os indica cómo realizar la gestión de estos errores. + if operador == "+": + return sumar(num1, num2) + elif operador == "-": + return restar(num1, num2) + elif operador == "x" or operador == "*": + return multiplicar(num1, num2) + elif operador == "/" or operador == ":": + return dividir(num1, num2) + elif operador == "**" or operador == "exp": + return potencia(num1, num2) + else: + mostrar_error(4) + return None + + return resultado + + + +def obtener_operaciones() -> str: + """ + Devuelve una cadena con la lista de operaciones disponibles en la calculadora. + + Returns: + (str): cadena de caracteres con la información de las operaciones disponibles. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + """ + Operaciones disponibles: + ce => Reiniciar resultado a 0 + decimales => Establecer decimales en resultado + cadena vacía + => Pregunta si desea salir + calculo => Iniciar cálculo secuencial + + => Suma + - => Resta + x o * => Multiplicación + / o : => División + ** o exp => Potencia + cancelar => vovler sin actualizar resultado de la calculadora + cadena vacía + => volver actualizando resultado de la calculadora + """ + + +def realizar_calculo(): + """ + Realiza una secuencia de cálculos solicitando números y operadores al usuario. + + Args: + decimales (int): Número de decimales para el resultado. + resultado_almacenado (float): Valor almacenado en la calculadora. + + Returns: + float: Resultado final del cálculo o None si se cancela. + + Note: + * Dentro de esta función el usuario puede realizar cálculos secuenciales, es decir, + comenzará introduciendo un número, después un operador, y otro número... a partir + de aquí sobre el resultado acumulado, introducirá operador y número para seguir + realizando cálculos (ver ejemplos en README.md de la tarea en el repositorio de GitHub). + * El usuario es guiado para introducir números y operadores secuencialmente + para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el + resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado + de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el + resultado almacenado de la calculadora. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + + operador = None + resultado = None + realizando_calculos = True + + print("\n## Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo ##\n") + + while realizando_calculos: + entrada = pedir_entrada(f"\t (Cálculo = resultado) >> ") + + if entrada == "cancelar": + + + elif entrada == "": + + + elif entrada in OPERADORES: + operador = + + else: + # TODO: este código funciona cuando solucionéis que reconozca las variables resultado_almacenado y decimales. + # Pero no gestiona los posibles tipos de Excepciones que se pueden producir: + # - ValueError que debe mostrar el error que está en la posición 2 de MENSAJES_ERROR. + # - ZeroDivisionError que debe mostrar el error que está en la posición 5 de MENSAJES_ERROR. + # - Exception que debe mostrar el error que está en la posición 6 de MENSAJES_ERROR. + if entrada == "resultado": + entrada = resultado_almacenado + + try: + numero = float(entrada) + + if operador is not None: + if resultado is None: + resultado = 0 + resultado = round(calcular_operacion(resultado, numero, operador), decimales) + operador = None + + elif resultado is None: + resultado = numero + + else: + mostrar_error(3) + except: + + +def main(): + """ + Función principal de la calculadora. Gestiona la entrada del usuario y coordina las operaciones. + + Note: + El flujo del programa es el siguiente: + + 1. Inicia la calculadora mostrando el resultado almacenado por defecto (0.00). + + 2. El usuario ingresa un comando, que puede ser: + - "lista" para ver todas las operaciones disponibles. + - "ce" para reiniciar el resultado almacenado a 0. + - "decimales " para establecer el número de decimales mostrados en el resultado. + - "calculo" para iniciar una secuencia de cálculo paso a paso. + - Una entrada vacía y pulsa la tecla para salir de la calculadora. + + 3. Según el comando ingresado: + - El programa realiza la operación o ejecuta la acción indicada. + - Al ingresar "calculo": + * El usuario es guiado para introducir números y operadores secuencialmente para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el resultado almacenado de la calculadora. + + 4. La calculadora sigue ejecutándose hasta que el usuario confirma la salida al ingresar una entrada vacía y pulsar . + + 5. Finalmente, se limpia la pantalla, el programa se despide con el mensaje "\n\nBye, bye...\n\n" y termina. + """ + # TODO: Corrige los errores y haz que el main funcione correctamente... + + decimales = 2 + resultado = 0.0 + + while not desea_salir: + + pedir_entrada(f"Operación (RES => resultado) >> ") + + if entrada == "": + pedir_entrada("¿Desea salir de la calculadora? (s/n) ") + + elif entrada == "lista": + obtener_operaciones + + elif entrada == "ce": + + + elif entrada.startswith("decimales"): + # Extraemos las posiciones decimales y las convertimos a un valor entero + decimales = str(entrada.split()[1]) + print(f"Decimales configurados a {decimales}.") + + elif entrada == "calculo": + realizar_calculo(decimales, resultado) + + else: + mostrar_error diff --git a/daw1b_calculadora/beni_calculadora_alumnos.py b/daw1b_calculadora/beni_calculadora_alumnos.py new file mode 100644 index 0000000..208c74e --- /dev/null +++ b/daw1b_calculadora/beni_calculadora_alumnos.py @@ -0,0 +1,574 @@ +# TODO: ATENCIÓN!!! +# 1. Importar los paquetes necesarios +# 2. Usar la función mostrar_error para imprimir los errores por consola. +# 3. Los comentarios TODO os ayudan a resolver cada apartado de esta prueba. +# 4. CADA función SOLO puede tener una instrucción return. +# 5. En test_calculadora_alumnos.py crear el test unitario para la función es_resultado_negativo y hacer que todos los test unitarios se cumplan. + +import os +import time + +# Mensajes de error predefinidos +MENSAJES_ERROR = ( + "Problemas al intentar limpiar la pantalla {error}", + "Error al configurar los decimales. Formato: decimales .", + "Entrada no válida. Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo.", + "Error: Introduzca un operador antes de otro número.", + "Comando no reconocido. Escriba 'lista' para ver las operaciones disponibles.", + "Error: no es posible la división por 0! Introduzca otro valor diferente a 0...", + "Se produjo un error: {error}" +) + +# Operadores soportados por la calculadora +OPERADORES = ("+", "-", "x", "*", "/", ":", "**", "exp") +# TODO: Ayuda: incluye en esta constante los símbolos que reconocerá la aplicación para el cálculo de las operaciones: +# '+' para la suma. +# '-' para la resta. +# 'x' o '*' para la multiplicación. +# '/' o ':' para la división. +# '**' o 'exp' para la potencia. + + + +def limpiar_pantalla(): + """ + Limpia la consola según el sistema operativo. + """ + # TODO: El desarrollo de esta función está incompleto y con errores. + try: + os.system("clear" if os.name == "posix" else "cls") + # Otra forma de expresar la misma instrucción sería la siguiente: + # if os.name = posix: + # os.system(clear) + # else: + # os.system(cls) + except Exception as e: + print() + + +def pausa(): + """ + Pausa la ejecución del programa hasta que se pulse ENTER... "\nPresione ENTER para continuar..." + """ + # TODO: Desarrollar esta función según su documentación. + + input("\nPresione ENTER para continuar...") + + +def mostrar_error(indice_error: int, msj_error = None): + """ + Muestra un mensaje de error en la consola. + + Args: + indice_error (int): Índice del mensaje de error en MENSAJES_ERROR. + msj_error (str, opcional): Texto adicional para personalizar el mensaje de error. + """ + # TODO: + # 1. Corrige el error que existe a la hora de acceder a los mensajes de error que están en la constante + # MENSAJES_ERROR. A los elementos de una tupla se accede igual que a los caracteres de una + # cadena de caracteres. + # 2. Completa el código de esta función para que controle específicamente las excepciones IndexError y + # muestre el mensaje: "\n*ERROR* Mensaje de error no definido.\n" + # 3. También se pide que se controle cualquier otra excepción que se pueda producir y muestre el mensaje: + # "\n*ERROR* Problemas al mostrar error!\n{e}\n" + # 4. En esta función los mensajes de error deben mostrarse con print. + if msj_error != None: + + print(f"\n*ERROR* {MENSAJES_ERROR[indice_error]} {msj_error}\n") + + else: + + print(f"\n*ERROR* {MENSAJES_ERROR[indice_error]}\n") + + +def sumar(num1: float, num2: float) -> int: + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la suma de ambos. + """ + Realiza la suma de dos números. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la suma. + + """ + num1 = int(round(num1)) + num2 = int(round(num2)) + + resultado = num1 + num2 + + return resultado + +def restar(num1: float, num2: float) -> int: + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la resta de ambos. + """ + Realiza la resta de dos números. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la resta. + + """ + num1 = int(round(num1)) + num2 = int(round(num2)) + + resultado = num1 - num2 + + return resultado + +def es_resultado_negativo(num1: float, num2: float) -> bool: + """Determina si el resultado de una operación entre num1 y num2 debe ser negativo.""" + # TODO: Realizar el desarrollo completo de esta función teniendo en cuenta la documentación y completándola también. + # Debe pasar las pruebas unitarias. + # Se trata de una función que os puede venir bien para utilizarla tanto en la función multiplicar, como en dividir. + # Ya que va a determinar si la multiplicación o división entre dos números debería ser de signo negativo o no. + + if num1 < 0 and num2 >= 0 or num1 >= 0 and num2 < 0: + + negativo = True + + else: + + negativo = False + + return negativo + +def multiplicar(num1:float, num2: float) -> int: + """ + Realiza la multiplicación ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la multiplicación. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de multiplicación de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la multiplicación con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 * 3.33, deberá convertirse en 5 * 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 * -5 = 25 + # 6. OBLIGATORIO usar un bucle for. + # 7. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + num1 = round(num1) + num2 = round(num2) + + if es_resultado_negativo(num1, num2) == True: + + num1 = str(num1) + num2 = str(num2) + + + if str(num1).startswith("-") == True: + + num1 = num1[1:] + + if str(num2).startswith("-") == True: + + num2 = num2[1:] + + num1 = int(num1) + num2 = int(num2) + resultado = num1 + + for i in range (1, num2): + resultado += num1 + + resultado = "-" + str(resultado) + + else: + + num1 = str(num1) + num2 = str(num2) + + if str(num1).startswith("-") == True: + + num1 = num1[1:] + + if str(num2).startswith("-") == True: + + num2 = num2[1:] + + num1 = int(num1) + num2 = int(num2) + resultado = num1 + + for i in range (1, num2): + resultado += num1 + + + resultado = int(resultado) + + return resultado + +def dividir(num1: float, num2: float) -> int: + """ + Realiza la división ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Dividendo. + num2 (float): Divisor. + + Returns: + int: Resultado de la división. + + Raises: + ZeroDivisionError: Si el divisor es cero. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de división de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la división con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 / 3.33, deberá convertirse en 5 / 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 / -5 = 1 + # 6. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + resultado = 0 + num1 = round(num1) + num2 = round(num2) + + if es_resultado_negativo(num1, num2) == True: + + num1 = str(num1) + num2 = str(num2) + + if str(num1).startswith("-") == True: + + num1 = num1[1:] + + if str(num2).startswith("-") == True: + + num2 = num2[1:] + + num1 = int(num1) + num2 = int(num2) + + while num1 >= num2: # Mientras sea divisible (Dividendo mayor que divisor) se hará la operación. + num1 -= num2 # Se irá restando el divisor al dividendo, ya que eso nos diría que es divisible. + resultado += 1 # Cada vez que el divisor quepa es un número más al cociente. + + resultado = "-" + str(resultado) + + else: + + num1 = str(num1) + num2 = str(num2) + + if str(num1).startswith("-") == True: + + num1 = num1[1:] + + if str(num2).startswith("-") == True: + + num2 = num2[1:] + + num1 = int(num1) + num2 = int(num2) + + while num1 >= num2: # Mientras sea divisible (Dividendo mayor que divisor) se hará la operación. + num1 -= num2 # Se irá restando el divisor al dividendo, ya que eso nos diría que es divisible. + resultado += 1 # Cada vez que el divisor quepa es un número más al cociente. + + resultado = int(resultado) + + return resultado + +def potencia(num1: float, num2: float) -> int: + # TODO: + # 1. Realizar el desarrollo completo de esta función y su documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. PREMISAS a tener en cuenta: + # - Cualquier número elevado a 0 da como resultado 1. + # - Para simplificar esta función, vamos a suponer que un número elevado a un + # exponente negativo siempre dará 0 (aunque en realidad no es así matemáticamente) + # 4. Utiliza la función de multiplicar para realizar los cálculos que te + # harán falta en esta función (RECUERDA que no puedes usar directamente los operadores + # de Python para la multiplicación y división). + # 5. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + num1 = int(num1) + num2 = int(num2) + resultado = num1 + + if num2 == 0: + + resultado = 1 + + elif num2 < 0: + + resultado = 0 + + else: + + for i in range (1, num2): + + resultado = multiplicar(resultado, num1) + + + + return resultado + +def pedir_entrada(msj: str) -> str: + """ + Pide al usuario una entrada, elimina espacios por delante y por detrás y la convierte a minúsculas. + + Args: + msj (str): Mensaje para solicitar la entrada. + + Returns: + str: Entrada del usuario. + """ + # TODO: El desarrollo de esta función está incompleto, debéis terminarla teniendo en cuenta la documentación + + entrada = input(msj).strip().lower() + + + return entrada + + +def calcular_operacion(num1: float, num2: float, operador: str) -> float: + """ + Realiza la operación especificada entre num1 y num2 dependiendo del valor del operador. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + float: Resultado de la operación. + + Raises: + ZeroDivisionError: Si el divisor es cero. + """ + # TODO: El desarrollo de esta función está incompleto... completadla teniendo en cuenta la documentación + # y que debe realizar las llamadas adecuadas a las funciones ya creadas para realizar los distintos + # cálculos... sumar, restar, multiplicar, dividir y potencia. + # IMPORTANTE: Si hacemos caso a la documentación de esta función, NO debéis capturar la excepción + # ZeroDivisionError aquí, sino que hay que dejadla que se propague a la función llamante, realizar_calculo(), + # dónde se os indica cómo realizar la gestión de estos errores. + + if operador == "x" or operador == "*": + resultado = multiplicar(num1, num2) + + elif operador == "/" or operador == ":": + + if num2 == 0: + raise ZeroDivisionError + + resultado = dividir(num1, num2) + + elif operador == "**" or operador == "exp": + + resultado = potencia(num1, num2) + + elif operador == "+": + + resultado = sumar(num1, num2) + + elif operador == "-": + + resultado = restar(num1, num2) + + return resultado + + + +def obtener_operaciones() -> str: + """ + Devuelve una cadena con la lista de operaciones disponibles en la calculadora. + + Returns: + (str): cadena de caracteres con la información de las operaciones disponibles. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + """ + Operaciones disponibles: + ce => Reiniciar resultado a 0 + decimales => Establecer decimales en resultado + cadena vacía + => Pregunta si desea salir + calculo => Iniciar cálculo secuencial + + => Suma + - => Resta + x o * => Multiplicación + / o : => División + ** o exp => Potencia + cancelar => vovler sin actualizar resultado de la calculadora + cadena vacía + => volver actualizando resultado de la calculadora + """ + lista = "\nOperaciones disponibles: \n ce => Reiniciar resultado a 0 \n decimales => Establecer decimales en resultado \n cadena vacía + => Pregunta si desea salir \n calculo => Iniciar cálculo secuencial \n + => Suma \n - => Resta \n x o * => Multiplicación \n / o : => División \n ** o exp => Potencia \n cancelar => vovler sin actualizar resultado de la calculadora \n cadena vacía + => volver actualizando resultado de la calculadora" + return lista + +def realizar_calculo(decimales): + """ + Realiza una secuencia de cálculos solicitando números y operadores al usuario. + + Args: + decimales (int): Número de decimales para el resultado. + resultado_almacenado (float): Valor almacenado en la calculadora. + + Returns: + float: Resultado final del cálculo o None si se cancela. + + Note: + * Dentro de esta función el usuario puede realizar cálculos secuenciales, es decir, + comenzará introduciendo un número, después un operador, y otro número... a partir + de aquí sobre el resultado acumulado, introducirá operador y número para seguir + realizando cálculos (ver ejemplos en README.md de la tarea en el repositorio de GitHub). + * El usuario es guiado para introducir números y operadores secuencialmente + para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el + resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado + de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el + resultado almacenado de la calculadora. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + + operador = None + resultado = None + realizando_calculos = False + resultado_almacenado = 0 + + print("\n## Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo ##\n") + + while not realizando_calculos: + entrada = pedir_entrada(f"\t (Cálculo = {resultado}) >> ") + + if entrada == "cancelar": + operador = None + numero = None + + elif entrada == "": + realizando_calculos = True + + elif entrada in OPERADORES: + operador = entrada + + else: + # TODO: este código funciona cuando solucionéis que reconozca las variables resultado_almacenado y decimales. + # Pero no gestiona los posibles tipos de Excepciones que se pueden producir: + # - ValueError que debe mostrar el error que está en la posición 2 de MENSAJES_ERROR. + # - ZeroDivisionError que debe mostrar el error que está en la posición 5 de MENSAJES_ERROR. + # - Exception que debe mostrar el error que está en la posición 6 de MENSAJES_ERROR. + if entrada == "resultado": + entrada = resultado_almacenado + + try: + numero = float(entrada) + + if operador is not None: + if resultado is None: + resultado = 0 + resultado = round(calcular_operacion(resultado, numero, operador), decimales) + operador = None + + elif resultado is None: + resultado = numero + + else: + mostrar_error(3) + + except ValueError: + mostrar_error(2) + + except ZeroDivisionError: + mostrar_error(5) + + except Exception: + mostrar_error(6) + + + +def main(): + """ + Función principal de la calculadora. Gestiona la entrada del usuario y coordina las operaciones. + + Note: + El flujo del programa es el siguiente: + + 1. Inicia la calculadora mostrando el resultado almacenado por defecto (0.00). + + 2. El usuario ingresa un comando, que puede ser: + - "lista" para ver todas las operaciones disponibles. + - "ce" para reiniciar el resultado almacenado a 0. + - "decimales " para establecer el número de decimales mostrados en el resultado. + - "calculo" para iniciar una secuencia de cálculo paso a paso. + - Una entrada vacía y pulsa la tecla para salir de la calculadora. + + 3. Según el comando ingresado: + - El programa realiza la operación o ejecuta la acción indicada. + - Al ingresar "calculo": + * El usuario es guiado para introducir números y operadores secuencialmente para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el resultado almacenado de la calculadora. + + 4. La calculadora sigue ejecutándose hasta que el usuario confirma la salida al ingresar una entrada vacía y pulsar . + + 5. Finalmente, se limpia la pantalla, el programa se despide con el mensaje "\n\nBye, bye...\n\n" y termina. + """ + # TODO: Corrige los errores y haz que el main funcione correctamente... + + decimales = 2 + resultado = 0.0 + desea_salir = False + + while not desea_salir: + try: + limpiar_pantalla() + + entrada = pedir_entrada(f"Operación (RES => {resultado}) >> ") + + if entrada == "": + if pedir_entrada("¿Desea salir de la calculadora? (s/n): ") == "s": + desea_salir = True + + elif entrada == "lista": + print(obtener_operaciones()) + pausa() + + elif entrada == "ce": + resultado = 0.0 + + elif entrada.startswith("decimales"): + # Extraemos las posiciones decimales y las convertimos a un valor entero + decimales = str(entrada.split()[1]) + print(f"Decimales configurados a {decimales}.") + pausa() + + elif entrada == "calculo": + resultado = realizar_calculo(decimales) + + else: + mostrar_error(2) + pausa() + + except Exception: + mostrar_error(6) + pausa() + + limpiar_pantalla() + print ("\n\nBye, bye...\n\n") + +if __name__ == "__main__": + main() diff --git a/daw1b_calculadora/daniel_calculadora_alumnos.py b/daw1b_calculadora/daniel_calculadora_alumnos.py new file mode 100644 index 0000000..2698d51 --- /dev/null +++ b/daw1b_calculadora/daniel_calculadora_alumnos.py @@ -0,0 +1,522 @@ +# TODO: ATENCIÓN!!! +# 1. Importar los paquetes necesarios +# 2. Usar la función mostrar_error para imprimir los errores por consola. +# 3. Los comentarios TODO os ayudan a resolver cada apartado de esta prueba. +# 4. CADA función SOLO puede tener una instrucción return. +# 5. En test_calculadora_alumnos.py crear el test unitario para la función es_resultado_negativo y hacer que todos los test unitarios se cumplan. +import os, math + + +# Mensajes de error predefinidos +MENSAJES_ERROR = ( + "Problemas al intentar limpiar la pantalla {error}", + "Error al configurar los decimales. Formato: decimales .", + "Entrada no válida. Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo.", + "Error: Introduzca un operador antes de otro número.", + "Comando no reconocido. Escriba 'lista' para ver las operaciones disponibles.", + "Error: no es posible la división por 0! Introduzca otro valor diferente a 0...", + "Se produjo un error: {error}" +) + +# Operadores soportados por la calculadora +OPERADORES = ("+","-","x","*","/",":","**","exp") +# TODO: Ayuda: incluye en esta constante los símbolos que reconocerá la aplicación para el cálculo de las operaciones: +# '+' para la suma. +# '-' para la resta. +# 'x' o '*' para la multiplicación. +# '/' o ':' para la división. +# '**' o 'exp' para la potencia. + + + +def limpiar_pantalla(): + """ + Limpia la consola según el sistema operativo. + """ + # TODO: El desarrollo de esta función está incompleto y con errores. + try: + os.system("clear" if os.name == "posix" else "cls") + # Otra forma de expresar la misma instrucción sería la siguiente: + # if os.name = posix: + # os.system(clear) + # else: + # os.system(cls) + except Exception as e: + mostrar_error(0,e) + + +def pausa(): + """ + Pausa la ejecución del programa hasta que se pulse ENTER... "\nPresione ENTER para continuar..." + """ + input("\nPresione ENTER para continuar...") + # TODO: Desarrollar esta función según su documentación. + + +def mostrar_error(indice_error: int, msj_error = None): + """ + Muestra un mensaje de error en la consola. + + Args: + indice_error (int): Índice del mensaje de error en MENSAJES_ERROR. + msj_error (str, opcional): Texto adicional para personalizar el mensaje de error. + """ + # TODO: + # 1. Corrige el error que existe a la hora de acceder a los mensajes de error que están en la constante + # MENSAJES_ERROR. A los elementos de una tupla se accede igual que a los caracteres de una + # cadena de caracteres. + # 2. Completa el código de esta función para que controle específicamente las excepciones IndexError y + # muestre el mensaje: "\n*ERROR* Mensaje de error no definido.\n" + # 3. También se pide que se controle cualquier otra excepción que se pueda producir y muestre el mensaje: + # "\n*ERROR* Problemas al mostrar error!\n{e}\n" + # 4. En esta función los mensajes de error deben mostrarse con print. + + try: + if msj_error != None: + print(f"\n*ERROR* {(MENSAJES_ERROR[indice_error]).format(error = msj_error)}\n") # parentesis añadidos + else: + print(f"\n*ERROR* {MENSAJES_ERROR[indice_error]}\n") + except IndexError as i: + print(f"\n*ERROR* Problemas al mostrar error!\n{i}\n") + except Exception as e: + print (f"\n*ERROR* Problemas al mostrar error!\n{e}\n") + + +def sumar(num1: float, num2: float): + """ + Suma los dos valores + + Args: + num1 (float): primer número + num2 (float): segundo número + + Returns: + float: el resultado de la suma + """ + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la suma de ambos. + return num1+num2 + + +def restar(num1: float, num2: float) -> float: + """ + Resta los dos valores + + Args: + num1 (float): primer número + num2 (float): segundo número + + Returns: + float: el resultado de la resta + """ + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la suma de ambos. + return num1-num2 + + + +def es_resultado_negativo(num1: float, num2: float) -> bool: + """Determina si el resultado de una operación entre num1 y num2 debe ser negativo.""" + # TODO: Realizar el desarrollo completo de esta función teniendo en cuenta la documentación y completándola también. + # Debe pasar las pruebas unitarias. + # Se trata de una función que os puede venir bien para utilizarla tanto en la función multiplicar, como en dividir. + # Ya que va a determinar si la multiplicación o división entre dos números debería ser de signo negativo o no. + if (num1*num2) <0 and (num1/num2)<0: + return True + else: + return False + + + +def redondear(num: float) -> int: + """ Redondea el número + Args: + num (float): Número decimal + Returns: + int: El número redondeado + """ + num = (str(num)).split(".") + parte_entera = int(num[0]) + parte_decimal = float("0." + str(num[1])) + if round(parte_decimal,2) >= 0.50: + return parte_entera + 1 + else: + return parte_entera + +def multiplicar(num1: float, num2: float) -> int: + """ + Realiza la multiplicación ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la multiplicación. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + """if (str(num1)).count("-") > 1: + num1 = (str(num1)).replace("-","") + if (str(num2)).count("-") > 1: + num2 = (str(num2)).replace("-","")""" + negativo = False + if es_resultado_negativo(num1, num2): + negativo = True + if num1 < 0: + num1 = float((str(num1)).replace("-","")) + if num2 < 0: + num2 = float((str(num2)).replace("-","")) + + if (str(num1)).count(".") > 0: + num1 = redondear(num1) + if (str(num2)).count(".") > 0: + num2 = redondear(num2) + + + """if num1 < 0 and num2 < 0: + num1 = (str(num1)).replace("-","") + num2 = (str(num2)).replace("-","") + negativo = False + elif num1 < 0: + num1 = (str(num1)).replace("-","") + negativo = True + elif num2 < 0: + num2 = (str(num2)).replace("-","") + negativo = True""" + resultado = 0 + if num1 > num2: + for i in range (1,num1+1): # suma el número el número de veces que es num2 + resultado += num2 + else: + for i in range (1,num2+1): # suma el número el número de veces que es num2 + resultado += num1 + + if negativo: # si el resultado era negativo le añade el menos + resultado = "-" + str(resultado) + return int(resultado) + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de multiplicación de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la multiplicación con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 * 3.33, deberá convertirse en 5 * 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 * -5 = 25 + # 6. OBLIGATORIO usar un bucle for. + # 7. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + + +def dividir(num1: float, num2: float) -> int: + """ + Realiza la división ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Dividendo. + num2 (float): Divisor. + + Returns: + int: Resultado de la división. + + Raises: + ZeroDivisionError: Si el divisor es cero. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + if (str(num1)).count(".") > 0: + num1 = redondear(num1) + if (str(num2)).count(".") > 0: + num2 = redondear(num2) + + negativo = False + if es_resultado_negativo(num1, num2): + negativo = True + num1 = int((str(num1)).replace("-","")) + num2 = int((str(num2)).replace("-","")) + contador = 0 + if num2 == 0: + raise ZeroDivisionError + for i in range (num2,num1+1,num2): #recorre desde num2 a num1 (de num2 en num2) y cada vez suma uno al contador + contador +=1 + if negativo: + contador = int("-" + str(contador) ) + return contador + + + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de división de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la división con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 / 3.33, deberá convertirse en 5 / 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 / -5 = 1 + # 6. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + +def potencia(num1: float, num2: float) -> int: # llamar a multiplicar + """ + Realiza la potencia + + Args: + num1 (float): primer numero + num1 (float): segundo numero + Returns: + int: el resultado de la operación + """ + num1 = num1; num2 = num2 + if (str(num1)).count(".") > 0: + num1 = redondear(num1) + if (str(num2)).count(".") > 0: + num2 = redondear(num2) + if num2 == 0: + return 1 + elif num2 < 0: + return 0 + else: + resultado = abs(num1) + contador = num2 - 1 + while contador > 0: + resultado = multiplicar(abs(num1), resultado) + contador -= 1 + + if num1< 0 and num2 % 2 != 0: + resultado = "-" + str(resultado) + return int(resultado) + + # TODO: + # 1. Realizar el desarrollo completo de esta función y su documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. PREMISAS a tener en cuenta: + # - Cualquier número elevado a 0 da como resultado 1. + # - Para simplificar esta función, vamos a suponer que un número elevado a un + # exponente negativo siempre dará 0 (aunque en realidad no es así matemáticamente) + # 4. Utiliza la función de multiplicar para realizar los cálculos que te + # harán falta en esta función (RECUERDA que no puedes usar directamente los operadores + # de Python para la multiplicación y división). + # 5. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + +def pedir_entrada(msj: str) -> str: + """ + Pide al usuario una entrada, elimina espacios por delante y por detrás y la convierte a minúsculas. + + Args: + msj (str): Mensaje para solicitar la entrada. + + Returns: + str: Entrada del usuario. + """ + entrada = input(msj).strip().lower() + # TODO: El desarrollo de esta función está incompleto, debéis terminarla teniendo en cuenta la documentación + return entrada + + +def calcular_operacion(num1: float, num2: float, operador: str) -> float: + """ + Realiza la operación especificada entre num1 y num2 dependiendo del valor del operador. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + float: Resultado de la operación. + + Raises: + ZeroDivisionError: Si el divisor es cero. + """ + if operador == "+": + resultado = sumar(num1, num2) + elif operador == "-": + resultado = restar(num1, num2) + elif operador == "*" or operador == "x": + resultado = multiplicar(num1, num2) + elif operador == "/" or operador == ":": + resultado = dividir(num1, num2) + elif operador == "**" or operador == "exp": + resultado = potencia(num1, num2) + # TODO: El desarrollo de esta función está incompleto... completadla teniendo en cuenta la documentación + # y que debe realizar las llamadas adecuadas a las funciones ya creadas para realizar los distintos + # cálculos... sumar, restar, multiplicar, dividir y potencia. + # IMPORTANTE: Si hacemos caso a la documentación de esta función, NO debéis capturar la excepción + # ZeroDivisionError aquí, sino que hay que dejadla que se propague a la función llamante, realizar_calculo(), + # dónde se os indica cómo realizar la gestión de estos errores. + + return resultado + + + +def obtener_operaciones() -> str: + """ + Devuelve una cadena con la lista de operaciones disponibles en la calculadora. + + Returns: + (str): cadena de caracteres con la información de las operaciones disponibles. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + return """ + Operaciones disponibles: + ce => Reiniciar resultado a 0 + decimales => Establecer decimales en resultado + cadena vacía + => Pregunta si desea salir + calculo => Iniciar cálculo secuencial + + => Suma + - => Resta + x o * => Multiplicación + / o : => División + ** o exp => Potencia + cancelar => vovler sin actualizar resultado de la calculadora + cadena vacía + => volver actualizando resultado de la calculadora + """ + + +def realizar_calculo(decimales: int, resultado_almacenado: float) -> float: + """ + Realiza una secuencia de cálculos solicitando números y operadores al usuario. + + Args: + decimales (int): Número de decimales para el resultado. + resultado_almacenado (float): Valor almacenado en la calculadora. + + Returns: + float: Resultado final del cálculo o None si se cancela. + + Note: + * Dentro de esta función el usuario puede realizar cálculos secuenciales, es decir, + comenzará introduciendo un número, después un operador, y otro número... a partir + de aquí sobre el resultado acumulado, introducirá operador y número para seguir + realizando cálculos (ver ejemplos en README.md de la tarea en el repositorio de GitHub). + * El usuario es guiado para introducir números y operadores secuencialmente + para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el + resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado + de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el + resultado almacenado de la calculadora. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + + operador = None + resultado = 0 + realizando_calculos = True + + print("\n## Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo ##\n") + num1 = float(pedir_entrada(f"\t (Cálculo = {resultado}) número>> ")); resultado = num1 + operador = pedir_entrada(f"\t (Cálculo = {resultado}) operación>> ") + num2 = float(pedir_entrada(f"\t (Cálculo = {resultado}) número>> ")) + resultado = calcular_operacion(resultado, num2, operador) + + while realizando_calculos: + resultado_almacenado = resultado + entrada = pedir_entrada(f"\t (Cálculo = {resultado}) operación>> ") + + if entrada == "cancelar": + realizando_calculos = False + + elif entrada == "": + return resultado + + elif entrada in OPERADORES: + operador = entrada + entrada = float(pedir_entrada(f"\t (Cálculo = {resultado}) número>> ")) + resultado = calcular_operacion(resultado, entrada, operador) + + else: + # TODO: este código funciona cuando solucionéis que reconozca las variables resultado_almacenado y decimales. + # Pero no gestiona los posibles tipos de Excepciones que se pueden producir: + # - ValueError que debe mostrar el error que está en la posición 2 de MENSAJES_ERROR. + # - ZeroDivisionError que debe mostrar el error que está en la posición 5 de MENSAJES_ERROR. + # - Exception que debe mostrar el error que está en la posición 6 de MENSAJES_ERROR. + if entrada == "resultado": + entrada = resultado_almacenado + try: + numero = float(entrada) + + if operador is not None: + if resultado is None: + resultado = 0 + resultado = round(calcular_operacion(resultado, numero, operador), decimales) + operador = None + + elif resultado is None: + resultado = numero + + else: + mostrar_error(3) + except ValueError as v: + mostrar_error(2, v) + except ZeroDivisionError as z: + mostrar_error(5, z) + except Exception as e: + mostrar_error(6, e) + + + +def main(): + """ + Función principal de la calculadora. Gestiona la entrada del usuario y coordina las operaciones. + + Note: + El flujo del programa es el siguiente: + + 1. Inicia la calculadora mostrando el resultado almacenado por defecto (0.00). + + 2. El usuario ingresa un comando, que puede ser: + - "lista" para ver todas las operaciones disponibles. + - "ce" para reiniciar el resultado almacenado a 0. + - "decimales " para establecer el número de decimales mostrados en el resultado. + - "calculo" para iniciar una secuencia de cálculo paso a paso. + - Una entrada vacía y pulsa la tecla para salir de la calculadora. + + 3. Según el comando ingresado: + - El programa realiza la operación o ejecuta la acción indicada. + - Al ingresar "calculo": + * El usuario es guiado para introducir números y operadores secuencialmente para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el resultado almacenado de la calculadora. + + 4. La calculadora sigue ejecutándose hasta que el usuario confirma la salida al ingresar una entrada vacía y pulsar . + + 5. Finalmente, se limpia la pantalla, el programa se despide con el mensaje "\n\nBye, bye...\n\n" y termina. + """ + # TODO: Corrige los errores y haz que el main funcione correctamente... + + decimales = 2 + resultado = 0.0 + desea_salir = False + + while not desea_salir: + + entrada = pedir_entrada(f"Operación (RES => {resultado}) >> ") + + if entrada == "": + entrada = pedir_entrada("¿Desea salir de la calculadora? (s/n) ") + if entrada in ("s","si","sí"): + desea_salir = True + + elif entrada == "lista": + print(obtener_operaciones()) + + elif entrada == "ce": + resultado = 0 + + elif entrada.startswith("decimales"): + # Extraemos las posiciones decimales y las convertimos a un valor entero + decimales = str(entrada.split(" ")[1]) + print(f"Decimales configurados a {decimales}.") + + elif entrada == "calculo": + resultado = realizar_calculo(decimales, resultado) + + else: + mostrar_error(2) + + limpiar_pantalla() + +if __name__ == "__main__": + main() diff --git a/daw1b_calculadora/david_calculadora_alumnos.py b/daw1b_calculadora/david_calculadora_alumnos.py new file mode 100644 index 0000000..972f4da --- /dev/null +++ b/daw1b_calculadora/david_calculadora_alumnos.py @@ -0,0 +1,521 @@ +# TODO: ATENCIÓN!!! +# 1. Importar los paquetes necesarios +# 2. Usar la función mostrar_error para imprimir los errores por consola. +# 3. Los comentarios TODO os ayudan a resolver cada apartado de esta prueba. +# 4. CADA función SOLO puede tener una instrucción return. +# 5. En test_calculadora_alumnos.py crear el test unitario para la función es_resultado_negativo y hacer que todos los test unitarios se cumplan. +import os + + +# Mensajes de error predefinidos +MENSAJES_ERROR = ( + "Problemas al intentar limpiar la pantalla {error}", + "Error al configurar los decimales. Formato: decimales .", + "Entrada no válida. Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo.", + "Error: Introduzca un operador antes de otro número.", + "Comando no reconocido. Escriba 'lista' para ver las operaciones disponibles.", + "Error: no es posible la división por 0! Introduzca otro valor diferente a 0...", + "Se produjo un error: {error}" +) + +# Operadores soportados por la calculadora +OPERADORES = "+", "-", "x", "*", "/", ":", "**", "exp" +# DONE: Ayuda: incluye en esta constante los símbolos que reconocerá la aplicación para el cálculo de las operaciones: +# '+' para la suma. +# '-' para la resta. +# 'x' o '*' para la multiplicación. +# '/' o ':' para la división. +# '**' o 'exp' para la potencia. + + + +def limpiar_pantalla(): + """ + Limpia la consola según el sistema operativo. + """ + # DONE: El desarrollo de esta función está incompleto y con errores. + try: + os.system("clear" if os.name == "posix" else "cls") + # Otra forma de expresar la misma instrucción sería la siguiente: + # if os.name = posix: + # os.system(clear) + # else: + # os.system(cls) + except Exception as e: + mostrar_error(0, e) + + + +def pausa(): + """ + Pausa la ejecución del programa hasta que se pulse ENTER... "\nPresione ENTER para continuar..." + """ + input("\nPresione ENTER para continuar...") + # DONE: Desarrollar esta función según su documentación. + + +def mostrar_error(indice_error: int, msj_error = None): + """ + Muestra un mensaje de error en la consola. + + Args: + indice_error (int): Índice del mensaje de error en MENSAJES_ERROR. + msj_error (str, opcional): Texto adicional para personalizar el mensaje de error. + """ + # DONE: + # 1. Corrige el error que existe a la hora de acceder a los mensajes de error que están en la constante + # MENSAJES_ERROR. A los elementos de una tupla se accede igual que a los caracteres de una + # cadena de caracteres. + # 2. Completa el código de esta función para que controle específicamente las excepciones IndexError y + # muestre el mensaje: "\n*ERROR* Mensaje de error no definido.\n" + # 3. También se pide que se controle cualquier otra excepción que se pueda producir y muestre el mensaje: + # "\n*ERROR* Problemas al mostrar error!\n{e}\n" + # 4. En esta función los mensajes de error deben mostrarse con print. + try: + if msj_error != None: + print(f"\n*ERROR* {MENSAJES_ERROR[indice_error].format(error = msj_error)}\n") + else: + print(f"\n*ERROR* {MENSAJES_ERROR[indice_error]}\n") + except IndexError: + print("\n*ERROR* Mensaje de error no definido.\n") + except Exception as e: + print(f"\n*ERROR* Problemas al mostrar error!\n{e}\n") + + +def sumar(num1: float, num2: float) -> float: + """ + Calcula la suma de los dos parámetros pasados en la función, retornando la suma de los mismo. + + Args: + num1 (float): El primer parámetro a sumar. + num2 (float): El segundo parámetro a sumar. + Returns: + float: La suma de los dos parámetros. + """ + return num1 + num2 + # DONE: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la suma de ambos. + + + +def restar(num1: float, num2: float) -> float: + """ + Calcula la resta de los dos parámetros pasados en la función, retornando la resta de los mismo. + + Args: + num1 (float): El primer parámetro a restar. + num2 (float): El segundo parámetro a restar. + Returns: + float: La resta de los dos parámetros. + """ + return num1 - num2 + # DONE: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la resta de ambos. + + + +def es_resultado_negativo(num1: float, num2: float) -> bool: + """ + Determina si el resultado de una operación entre num1 y num2 debe ser negativo. + + Args: + num1 (float): El primer número a comprobar. + num2 (float): El segundo número a comprobar. + + Returns: + bool: True si es negativo, False si no lo es. + """ + + # Variable que se actualizará dependiendo del resultado establecido en el condicional. + es_negativo = None + + if (num1 > 0 and num2 < 0) or (num1 < 0 and num2 > 0): + es_negativo = True + else: + es_negativo = False + + return es_negativo + # DONE: Realizar el desarrollo completo de esta función teniendo en cuenta la documentación y completándola también. + # Debe pasar las pruebas unitarias. + # Se trata de una función que os puede venir bien para utilizarla tanto en la función multiplicar, como en dividir. + # Ya que va a determinar si la multiplicación o división entre dos números debería ser de signo negativo o no. + + + +def multiplicar(num1: float, num2: float) -> int: + """ + Realiza la multiplicación ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la multiplicación. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + + # Variable para determinar si el resultado será negativo o positivo. + es_negativo = es_resultado_negativo(num1, num2) + + # Redondeamos y transformamos el valor de los números a su valor absoluto. + num1 = round(num1) + num2 = round(num2) + + num1 = abs(num1) + num2 = abs(num2) + + # Variable que irá almacenando el resultado por iteraciones del siguiente bucle para luego retornarlo + resultado = 0 + + if es_negativo: + # Bucle que itera valor:num2 de veces, sumando el valor de num1 a la variable resultado, simulando una multiplicación + # En el caso de negativo, añade un "-" al final. + for _ in range(num2): + resultado += num1 + resultado = f"-{resultado}" + else: + for _ in range(num2): + resultado += num1 + # Retorna la "multiplicación", forzándolo a ser un entero. + return int(resultado) + + # DONE: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de multiplicación de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la multiplicación con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 * 3.33, deberá convertirse en 5 * 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 * -5 = 25 + # 6. OBLIGATORIO usar un bucle for. + # 7. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + + +def dividir(num1: float, num2: float) -> int: + """ + Realiza la división ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Dividendo. + num2 (float): Divisor. + + Returns: + int: Resultado de la división. + + Raises: + ZeroDivisionError: Si el divisor es cero. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # Comprobamos que num2 no sea 0. Si lo es hace raise de ZeroDivisionError + if num2 == 0: + raise ZeroDivisionError("La división por 0 no es posible.") + + else: + # Variable para determinar si el resultado será negativo o positivo. + es_negativo = es_resultado_negativo(num1, num2) + + # Redondeamos y transformamos el valor de los números a su valor absoluto. + num1 = round(num1) + num2 = round(num2) + + num1 = abs(num1) + num2 = abs(num2) + + resultado = 0 + + # Bucle while que simula una división. Si el resultado de la variable es_negativo es True, incluirá un "-" en el resultado final. + if es_negativo: + while num1 >= num2: + num1 -= num2 + resultado += 1 + resultado = f"-{resultado}" + else: + while num1 >= num2: + num1 -= num2 + resultado +=1 + + # Retorna el resultado forzándolo a ser un entero. + return int(resultado) + + # DONE: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de división de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la división con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 / 3.33, deberá convertirse en 5 / 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 / -5 = 1 + # 6. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + +def potencia(num1: float, num2: float) -> int: + """ + + """ + if num2 == 0: + return 1 + elif num2 < 0: + return 0 + else: + return num1 ** num2 + + # DONE (xd): + # 1. Realizar el desarrollo completo de esta función y su documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. PREMISAS a tener en cuenta: + # - Cualquier número elevado a 0 da como resultado 1. + # - Para simplificar esta función, vamos a suponer que un número elevado a un + # exponente negativo siempre dará 0 (aunque en realidad no es así matemáticamente) + # 4. Utiliza la función de multiplicar para realizar los cálculos que te + # harán falta en esta función (RECUERDA que no puedes usar directamente los operadores + # de Python para la multiplicación y división). + # 5. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + + +def pedir_entrada(msj: str) -> str: + """ + Pide al usuario una entrada, elimina espacios por delante y por detrás y la convierte a minúsculas. + + Args: + msj (str): Mensaje para solicitar la entrada. + + Returns: + str: Entrada del usuario. + """ + # DONE: El desarrollo de esta función está incompleto, debéis terminarla teniendo en cuenta la documentación + return input(msj).strip().lower() + + +def calcular_operacion(num1: float, num2: float, operador: str) -> float: + """ + Realiza la operación especificada entre num1 y num2 dependiendo del valor del operador. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + float: Resultado de la operación. + + Raises: + ZeroDivisionError: Si el divisor es cero. + """ + # '+' para la suma. + # '-' para la resta. + # 'x' o '*' para la multiplicación. + # '/' o ':' para la división. + # '**' o 'exp' para la potencia. + + if operador == "+": + resultado = sumar(num1, num2) + elif operador == "-": + resultado = restar(num1, num2) + elif operador in "x*": + resultado = multiplicar(num1, num2) + elif operador in "/:": + resultado = dividir(num1, num2) + else: + resultado = potencia(num1, num2) + return resultado + # DONE: El desarrollo de esta función está incompleto... completadla teniendo en cuenta la documentación + # y que debe realizar las llamadas adecuadas a las funciones ya creadas para realizar los distintos + # cálculos... sumar, restar, multiplicar, dividir y potencia. + # IMPORTANTE: Si hacemos caso a la documentación de esta función, NO debéis capturar la excepción + # ZeroDivisionError aquí, sino que hay que dejadla que se propague a la función llamante, realizar_calculo(), + # dónde se os indica cómo realizar la gestión de estos errores. + + +def obtener_operaciones() -> str: + """ + Devuelve una cadena con la lista de operaciones disponibles en la calculadora. + + Returns: + (str): cadena de caracteres con la información de las operaciones disponibles. + """ + # DONE: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + # BUG: Arreglé un typo. + return """ + Operaciones disponibles: + ce => Reiniciar resultado a 0 + decimales => Establecer decimales en resultado + cadena vacía + => Pregunta si desea salir + calculo => Iniciar cálculo secuencial + + => Suma + - => Resta + x o * => Multiplicación + / o : => División + ** o exp => Potencia + cancelar => volver sin actualizar resultado de la calculadora + cadena vacía + => volver actualizando resultado de la calculadora + """ + + +def realizar_calculo(decimales: int, resultado_almacenado: float) -> float | bool: + """ + Realiza una secuencia de cálculos solicitando números y operadores al usuario. + + Args: + decimales (int): Número de decimales para el resultado. + resultado_almacenado (float): Valor almacenado en la calculadora. + + Returns: + float|bool: Resultado final del cálculo o None si se cancela. + + Note: + * Dentro de esta función el usuario puede realizar cálculos secuenciales, es decir, + comenzará introduciendo un número, después un operador, y otro número... a partir + de aquí sobre el resultado acumulado, introducirá operador y número para seguir + realizando cálculos (ver ejemplos en README.md de la tarea en el repositorio de GitHub). + * El usuario es guiado para introducir números y operadores secuencialmente + para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el + resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado + de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el + resultado almacenado de la calculadora. + """ + # DONE: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + + operador = None + resultado = None + realizando_calculos = True + + print("\n## Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo ##\n") + + while realizando_calculos: + # BUG: no se si debería mostrar 0, pero si no, muestra none. Es el arreglo que se me ocurrió. + entrada = pedir_entrada(f"\t (Cálculo = {0.0 if resultado is None else resultado:.{decimales}f}) >> ") + + if entrada == "cancelar": + resultado = None + realizando_calculos = False + print("Secuencia cancelada. Resultado almacenado sin cambios.") + + elif entrada == "": + realizando_calculos = False + + + elif entrada in OPERADORES: + operador = entrada + + else: + # DONE: este código funciona cuando solucionéis que reconozca las variables resultado_almacenado y decimales. + # Pero no gestiona los posibles tipos de Excepciones que se pueden producir: + # - ValueError que debe mostrar el error que está en la posición 2 de MENSAJES_ERROR. + # - ZeroDivisionError que debe mostrar el error que está en la posición 5 de MENSAJES_ERROR. + # - Exception que debe mostrar el error que está en la posición 6 de MENSAJES_ERROR. + if entrada == "resultado": + entrada = resultado_almacenado + + try: + numero = float(entrada) + + if operador is not None: + if resultado is None: + resultado = 0 + resultado = round(calcular_operacion(resultado, numero, operador), decimales) + operador = None + + elif resultado is None: + resultado = numero + + else: + mostrar_error(3) + except ValueError: + mostrar_error(2) + except ZeroDivisionError: + mostrar_error(5) + except Exception as e: + mostrar_error(6, e) + return resultado + + + +def main(): + """ + Función principal de la calculadora. Gestiona la entrada del usuario y coordina las operaciones. + + Note: + El flujo del programa es el siguiente: + + 1. Inicia la calculadora mostrando el resultado almacenado por defecto (0.00). + + 2. El usuario ingresa un comando, que puede ser: + - "lista" para ver todas las operaciones disponibles. + - "ce" para reiniciar el resultado almacenado a 0. + - "decimales " para establecer el número de decimales mostrados en el resultado. + - "calculo" para iniciar una secuencia de cálculo paso a paso. + - Una entrada vacía y pulsa la tecla para salir de la calculadora. + + 3. Según el comando ingresado: + - El programa realiza la operación o ejecuta la acción indicada. + - Al ingresar "calculo": + * El usuario es guiado para introducir números y operadores secuencialmente para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el resultado almacenado de la calculadora. + + 4. La calculadora sigue ejecutándose hasta que el usuario confirma la salida al ingresar una entrada vacía y pulsar . + + 5. Finalmente, se limpia la pantalla, el programa se despide con el mensaje "\n\nBye, bye...\n\n" y termina. + """ + # DONE: Corrige los errores y haz que el main funcione correctamente... + + decimales = 2 + resultado = 0.0 + desea_salir = False + + while not desea_salir: + limpiar_pantalla() + entrada = pedir_entrada(f"Operación (RES => {resultado:.{decimales}f}) >> ") + + #NOTE: Fixed + if entrada == "": + quiere_salir = pedir_entrada("¿Desea salir de la calculadora? (s/n) ") + if quiere_salir == "s": + desea_salir = True + + + elif entrada == "lista": + print(obtener_operaciones()) + + elif entrada == "ce": + resultado = 0 + + + elif entrada.startswith("decimales"): + # Extraemos las posiciones decimales y las convertimos a un valor entero + + # Añadido tryexcept de ValueError porque me cascó al introducir un negativo + # Añadido excepcion Index porque me dio error index al introducir decimales vacío + try: + decimales = str(entrada.split()[1]) + print(f"Decimales configurados a {decimales}.") + except ValueError: + mostrar_error(1) + except IndexError: + mostrar_error(1) + + elif entrada == "calculo": + guardar_calculo = realizar_calculo(decimales, resultado) + + if guardar_calculo != None: + resultado = guardar_calculo + + else: + mostrar_error(4) + + pausa() + + limpiar_pantalla() + print("\n\nBye, bye...\n\n") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/daw1b_calculadora/ezequiel_calculadora_alumnos.py b/daw1b_calculadora/ezequiel_calculadora_alumnos.py new file mode 100644 index 0000000..7dd7527 --- /dev/null +++ b/daw1b_calculadora/ezequiel_calculadora_alumnos.py @@ -0,0 +1,548 @@ +# TODO: ATENCIÓN!!! +# 1. Importar los paquetes necesarios +# 2. Usar la función mostrar_error para imprimir los errores por consola. +# 3. Los comentarios TODO os ayudan a resolver cada apartado de esta prueba. +# 4. CADA función SOLO puede tener una instrucción return. +# 5. En test_calculadora_alumnos.py crear el test unitario para la función es_resultado_negativo y hacer que todos los test unitarios se cumplan. + +# Dependencies +import os + +# Mensajes de error predefinidos +MENSAJES_ERROR = ( + "Problemas al intentar limpiar la pantalla: {error}", + "Error al configurar los decimales. Formato: decimales .", + "Entrada no válida. Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo.", + "Error: Introduzca un operador antes de otro número.", + "Comando no reconocido. Escriba 'lista' para ver las operaciones disponibles.", + "Error: no es posible la división por 0! Introduzca otro valor diferente a 0...", + "Se produjo un error: {error}" +) + +# Operadores soportados por la calculadora +OPERADORES = ( + "+", + "-", + "x", + "*", + "/", + ":", + "**", + "exp", +) + +# TODO: Ayuda: incluye en esta constante los símbolos que reconocerá la aplicación para el cálculo de las operaciones: +# '+' para la suma. +# '-' para la resta. +# 'x' o '*' para la multiplicación. +# '/' o ':' para la división. +# '**' o 'exp' para la potencia. + +def mostrar_error(indice_error: int, msj_error = None): + """ + Muestra un mensaje de error en la consola. + + Args: + indice_error (int): Índice del mensaje de error en MENSAJES_ERROR. + msj_error (str, opcional): Texto adicional para personalizar el mensaje de error. + """ + # TODO: + # 1. Corrige el error que existe a la hora de acceder a los mensajes de error que están en la constante + # MENSAJES_ERROR. A los elementos de una tupla se accede igual que a los caracteres de una + # cadena de caracteres. + # 2. Completa el código de esta función para que controle específicamente las excepciones IndexError y + # muestre el mensaje: "\n*ERROR* Mensaje de error no definido.\n" + # 3. También se pide que se controle cualquier otra excepción que se pueda producir y muestre el mensaje: + # "\n*ERROR* Problemas al mostrar error!\n{e}\n" + # 4. En esta función los mensajes de error deben mostrarse con print. + try: + if msj_error != None: + print(f"\n*ERROR* {MENSAJES_ERROR[indice_error].format(error = msj_error)}\n") + else: + print(f"\n*ERROR* {MENSAJES_ERROR[indice_error]}\n") + + except: + print("\n*ERROR* Mensaje de error no definido.\n") + +def limpiar_pantalla(): + """ + Limpia la consola según el sistema operativo. + """ + # TODO: El desarrollo de esta función está incompleto y con errores. + try: + os.system('cls') if os.name == 'nt' else os.system('clear') + except Exception as e: + mostrar_error(0, e) + + +def pausa(): + """ + Pausa la ejecución del programa hasta que se pulse ENTER... "\nPresione ENTER para continuar..." + """ + # TODO: Desarrollar esta función según su documentación. + input("\nPresione ENTER para continuar...") + + +def sumar(num1: float, num2: float) -> float: + """ + Realiza la suma de dos números + + Args: + n1 (float): Número 1 a sumar + n2 (float): Número 2 a ser sumado + + Returns: + float: La suma del Núemro 1 más el Número 2 (n1+n2) + """ + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la suma de ambos. + + return num1 + num2 + + +def restar(num1: float, num2: float) -> float: + """ + Realiza la resta de dos números + + Args: + n1 (float): Número 1 para restar + n2 (float): Número 2 a ser restado + + Returns: + float: La resta del Número 1 menos el Número 2 (n1-n2) + """ + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la resta de ambos. + + return num1 - num2 + + +def es_resultado_negativo(num1: float, num2: float) -> bool: + """Determina si el resultado de una operación entre num1 y num2 debe ser negativo.""" + # TODO: Realizar el desarrollo completo de esta función teniendo en cuenta la documentación y completándola también. + # Debe pasar las pruebas unitarias. + # Se trata de una función que os puede venir bien para utilizarla tanto en la función multiplicar, como en dividir. + # Ya que va a determinar si la multiplicación o división entre dos números debería ser de signo negativo o no. + num1_es_negativo = num1 < 0 + num2_es_negativo = num2 < 0 + + if num1_es_negativo != num2_es_negativo: + return True + else: + return False + +def multiplicar(num1: float, num2: float) -> int: + """ + Realiza la multiplicación ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la multiplicación. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de multiplicación de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la multiplicación con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 * 3.33, deberá convertirse en 5 * 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 * -5 = 25 + # 6. OBLIGATORIO usar un bucle for. + # 7. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + try: + es_negativo = es_resultado_negativo(num1, num2) + + num1 = abs(round(num1)) + num2 = abs(round(num2)) + + if num2 == 0 or num1 == 0: + resultado = 0 + else: + + resultado = num1 + + for _ in range(num2-1): + resultado = resultado + num1 + + except Exception as e: + print(e) + + else: + if es_negativo: + resultado = -resultado + else: + resultado = abs(resultado) + return resultado + +def dividir(num1: float, num2: float) -> int: + """ + Realiza la división ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Dividendo. + num2 (float): Divisor. + + Returns: + int: Resultado de la división. + + Raises: + ZeroDivisionError: Si el divisor es cero. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de división de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la división con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 / 3.33, deberá convertirse en 5 / 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 / -5 = 1 + # 6. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + es_negativo = es_resultado_negativo(num1, num2) # Llamamos a la función para comprobar si es negativo o no + + num1 = abs(round(num1)) + num2 = abs(round(num2)) + + resultado = 0 + + if num2 == 0: + raise ZeroDivisionError + + if num2 > num1: + resultado = 0 + + elif num2 == num1: + resultado = 1 + + else: + resultado_temp = num1 + counter = 0 + + while resultado_temp >= 0: + resultado_temp = resultado_temp - num2 + counter += 1 + + resultado = counter - 1 + + # En caso que alguno de los dos números sea negativo, cambiaremos el resultado a negativo, pues un número positivo entre un número negativo, debe retonar un número negativo. + if es_negativo: + resultado = -resultado + + return resultado + +def potencia(num1: float, num2: float) -> int: + """ + Realiza la potencia entre el num 1 y num2 (num1**num2) + + Args: + num1 (float): Base. + num2 (float): Exponente. + + Returns: + int: Resultado de la potencia. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función y su documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. PREMISAS a tener en cuenta: + # - Cualquier número elevado a 0 da como resultado 1. + # - Para simplificar esta función, vamos a suponer que un número elevado a un + # exponente negativo siempre dará 0 (aunque en realidad no es así matemáticamente) + # 4. Utiliza la función de multiplicar para realizar los cálculos que te + # harán falta en esta función (RECUERDA que no puedes usar directamente los operadores + # de Python para la multiplicación y división). + # 5. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + try: + if num2 == 0: + resultado = 1 + elif num2 < 0: + resultado = 0 + else: + num1_abs = abs(round(num1)) + num2_abs = abs(round(num2)) + resultado = 0 + + for _ in range(num2_abs-1): + multiplicacion = multiplicar(num1_abs, num1_abs) + resultado = resultado + multiplicacion + + if num2_abs % 2 != 0 and num1 < 0: + resultado = -resultado + + except Exception as e: + mostrar_error(6, e) + + else: + return resultado + +def pedir_entrada(msj: str) -> str: + """ + Pide al usuario una entrada, elimina espacios por delante y por detrás y la convierte a minúsculas. + + Args: + msj (str): Mensaje para solicitar la entrada. + + Returns: + str: Entrada del usuario. + """ + # TODO: El desarrollo de esta función está incompleto, debéis terminarla teniendo en cuenta la documentación + entrada = input(msj).strip().lower() + return entrada + + +def calcular_operacion(num1: float, num2: float, operador: str) -> float: + """ + Realiza la operación especificada entre num1 y num2 dependiendo del valor del operador. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + float: Resultado de la operación. + + Raises: + ZeroDivisionError: Si el divisor es cero. + """ + # TODO: El desarrollo de esta función está incompleto... completadla teniendo en cuenta la documentación + # y que debe realizar las llamadas adecuadas a las funciones ya creadas para realizar los distintos + # cálculos... sumar, restar, multiplicar, dividir y potencia. + # IMPORTANTE: Si hacemos caso a la documentación de esta función, NO debéis capturar la excepción + # ZeroDivisionError aquí, sino que hay que dejadla que se propague a la función llamante, realizar_calculo(), + # dónde se os indica cómo realizar la gestión de estos errores. + + if operador == "+": + resultado = sumar(num1, num2) + elif operador == "-": + resultado = restar(num1, num2) + elif operador == "x" or operador == "*": + resultado = multiplicar(num1, num2) + elif operador == "/" or operador == ":": + resultado = dividir(num1, num2) + # El Raises de ZeroDivisionError ya lo trae la "función dividir()", pues ahí en la documentación pide que se haga un Raise tambien. + # Asi que no he hecho otro Raise en esta funciíon "calcular_operacion()", pues al ya haber hecho un Raise lo capturará sin problemas "realizar_calculo()" + + elif operador == "**" or operador == "exp": + resultado = potencia(num1, num2) + + if resultado: + resultado = float(resultado) + + return resultado + + +def obtener_operaciones() -> str: + """ + Devuelve una cadena con la lista de operaciones disponibles en la calculadora. + + Returns: + (str): cadena de caracteres con la información de las operaciones disponibles. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + """ + Operaciones disponibles: + ce => Reiniciar resultado a 0 + decimales => Establecer decimales en resultado + cadena vacía + => Pregunta si desea salir + calculo => Iniciar cálculo secuencial + + => Suma + - => Resta + x o * => Multiplicación + / o : => División + ** o exp => Potencia + cancelar => volver sin actualizar resultado de la calculadora + cadena vacía + => volver actualizando resultado de la calculadora + """ + operaciones_disponibles = """Operaciones disponibles: + ce => Reiniciar resultado a 0 + decimales => Establecer decimales en resultado + cadena vacía + => Pregunta si desea salir + calculo => Iniciar cálculo secuencial + + => Suma + - => Resta + x o * => Multiplicación + / o : => División + ** o exp => Potencia + cancelar => volver sin actualizar resultado de la calculadora + cadena vacía + => volver actualizando resultado de la calculadora""" + + return operaciones_disponibles + + +def realizar_calculo(decimales: int, resultado_almacenado: float) -> float: + """ + Realiza una secuencia de cálculos solicitando números y operadores al usuario. + + Args: + decimales (int): Número de decimales para el resultado. + resultado_almacenado (float): Valor almacenado en la calculadora. + + Returns: + float: Resultado final del cálculo o None si se cancela. + + Note: + * Dentro de esta función el usuario puede realizar cálculos secuenciales, es decir, + comenzará introduciendo un número, después un operador, y otro número... a partir + de aquí sobre el resultado acumulado, introducirá operador y número para seguir + realizando cálculos (ver ejemplos en README.md de la tarea en el repositorio de GitHub). + * El usuario es guiado para introducir números y operadores secuencialmente + para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el + resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado + de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el + resultado almacenado de la calculadora. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + + operador = None + resultado = None + realizando_calculos = True + + print("\n## Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo ##\n") + + try: + + while realizando_calculos: + + if resultado == None: + entrada = pedir_entrada(f"\t (Cálculo = {0:.{decimales}f}) >> ") + else: + entrada = pedir_entrada(f"\t (Cálculo = {resultado:.{decimales}f}) >> ") + + if entrada == "cancelar": + print("Secuencia cancelada. Resultado almacenado sin cambios.") + realizando_calculos = False + + elif entrada == "": + return resultado + + elif entrada in OPERADORES: + operador = entrada + + else: + # TODO: este código funciona cuando solucionéis que reconozca las variables resultado_almacenado y decimales. + # Pero no gestiona los posibles tipos de Excepciones que se pueden producir: + # - ValueError que debe mostrar el error que está en la posición 2 de MENSAJES_ERROR. + # - ZeroDivisionError que debe mostrar el error que está en la posición 5 de MENSAJES_ERROR. + # - Exception que debe mostrar el error que está en la posición 6 de MENSAJES_ERROR. + if entrada == "resultado": + entrada = resultado_almacenado + + numero = float(entrada) + + if operador is not None: + + if resultado is None: + resultado = 0 + + resultado = round(calcular_operacion(resultado, numero, operador), decimales) + operador = None + + elif resultado is None: + resultado = numero + + else: + mostrar_error(3) + + except ValueError: + mostrar_error(2) + + except ZeroDivisionError: + mostrar_error(5) + + except Exception as e: + mostrar_error(6, e) + + else: + return resultado + + +def main(): + """ + Función principal de la calculadora. Gestiona la entrada del usuario y coordina las operaciones. + + Note: + El flujo del programa es el siguiente: + + 1. Inicia la calculadora mostrando el resultado almacenado por defecto (0.00). + + 2. El usuario ingresa un comando, que puede ser: + - "lista" para ver todas las operaciones disponibles. + - "ce" para reiniciar el resultado almacenado a 0. + - "decimales " para establecer el número de decimales mostrados en el resultado. + - "calculo" para iniciar una secuencia de cálculo paso a paso. + - Una entrada vacía y pulsa la tecla para salir de la calculadora. + + 3. Según el comando ingresado: + - El programa realiza la operación o ejecuta la acción indicada. + - Al ingresar "calculo": + * El usuario es guiado para introducir números y operadores secuencialmente para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el resultado almacenado de la calculadora. + + 4. La calculadora sigue ejecutándose hasta que el usuario confirma la salida al ingresar una entrada vacía y pulsar . + + 5. Finalmente, se limpia la pantalla, el programa se despide con el mensaje "\n\nBye, bye...\n\n" y termina. + """ + # TODO: Corrige los errores y haz que el main funcione correctamente... + + + decimales = 2 + resultado = 0.0 + desea_salir = False + + while not desea_salir: + limpiar_pantalla() + print("### CALCULADORA ###\n -----------\n") + + if resultado == None: + entrada = pedir_entrada(f"Operación (RES => {0:.{decimales}f}) >> ") + else: + entrada = pedir_entrada(f"Operación (RES => {resultado:.{decimales}f}) >> ") + + if entrada == "": + salir_opcion = pedir_entrada("¿Desea salir de la calculadora? (s/n) ") + if salir_opcion == "s" or salir_opcion == "si": + desea_salir = True + + elif entrada == "lista": + lista_operaciones = obtener_operaciones() + print(lista_operaciones) + pausa() + + elif entrada == "ce": + resultado = 0.0 + print("Resultado reiniciado a 0.") + pausa() + + elif entrada.startswith("decimales"): + # Extraemos las posiciones decimales y las convertimos a un valor entero + try: + decimales = int(str(entrada.split(' ')[1])) + print(f"Decimales configurados a {decimales}.") + pausa() + except IndexError: + mostrar_error(1) + + elif entrada == "calculo": + resultado = realizar_calculo(decimales, resultado) + pausa() + + else: + mostrar_error(4) + pausa() + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/daw1b_calculadora/ezequiel_calculadora_alumnos_bonus.py b/daw1b_calculadora/ezequiel_calculadora_alumnos_bonus.py new file mode 100644 index 0000000..0922d31 --- /dev/null +++ b/daw1b_calculadora/ezequiel_calculadora_alumnos_bonus.py @@ -0,0 +1,551 @@ +# TODO: ATENCIÓN!!! +# 1. Importar los paquetes necesarios +# 2. Usar la función mostrar_error para imprimir los errores por consola. +# 3. Los comentarios TODO os ayudan a resolver cada apartado de esta prueba. +# 4. CADA función SOLO puede tener una instrucción return. +# 5. En test_calculadora_alumnos.py crear el test unitario para la función es_resultado_negativo y hacer que todos los test unitarios se cumplan. + +# Dependencies +import os + +# Mensajes de error predefinidos +MENSAJES_ERROR = ( + "Problemas al intentar limpiar la pantalla: {error}", + "Error al configurar los decimales. Formato: decimales .", + "Entrada no válida. Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo.", + "Error: Introduzca un operador antes de otro número.", + "Comando no reconocido. Escriba 'lista' para ver las operaciones disponibles.", + "Error: no es posible la división por 0! Introduzca otro valor diferente a 0...", + "Se produjo un error: {error}" +) + +# Operadores soportados por la calculadora +OPERADORES = ( + "+", + "-", + "x", + "*", + "/", + ":", + "**", + "exp", +) + +# TODO: Ayuda: incluye en esta constante los símbolos que reconocerá la aplicación para el cálculo de las operaciones: +# '+' para la suma. +# '-' para la resta. +# 'x' o '*' para la multiplicación. +# '/' o ':' para la división. +# '**' o 'exp' para la potencia. + +def mostrar_error(indice_error: int, msj_error = None): + """ + Muestra un mensaje de error en la consola. + + Args: + indice_error (int): Índice del mensaje de error en MENSAJES_ERROR. + msj_error (str, opcional): Texto adicional para personalizar el mensaje de error. + """ + # TODO: + # 1. Corrige el error que existe a la hora de acceder a los mensajes de error que están en la constante + # MENSAJES_ERROR. A los elementos de una tupla se accede igual que a los caracteres de una + # cadena de caracteres. + # 2. Completa el código de esta función para que controle específicamente las excepciones IndexError y + # muestre el mensaje: "\n*ERROR* Mensaje de error no definido.\n" + # 3. También se pide que se controle cualquier otra excepción que se pueda producir y muestre el mensaje: + # "\n*ERROR* Problemas al mostrar error!\n{e}\n" + # 4. En esta función los mensajes de error deben mostrarse con print. + try: + if msj_error != None: + print(f"\n*ERROR* {MENSAJES_ERROR[indice_error].format(error = msj_error)}\n") + else: + print(f"\n*ERROR* {MENSAJES_ERROR[indice_error]}\n") + + except: + print("\n*ERROR* Mensaje de error no definido.\n") + +def limpiar_pantalla(): + """ + Limpia la consola según el sistema operativo. + """ + # TODO: El desarrollo de esta función está incompleto y con errores. + try: + os.system('cls') if os.name == 'nt' else os.system('clear') + except Exception as e: + mostrar_error(0, e) + + +def pausa(): + """ + Pausa la ejecución del programa hasta que se pulse ENTER... "\nPresione ENTER para continuar..." + """ + # TODO: Desarrollar esta función según su documentación. + input("\nPresione ENTER para continuar...") + + +def sumar(num1: float, num2: float) -> float: + """ + Realiza la suma de dos números + + Args: + n1 (float): Número 1 a sumar + n2 (float): Número 2 a ser sumado + + Returns: + float: La suma del Núemro 1 más el Número 2 (n1+n2) + """ + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la suma de ambos. + + return num1 + num2 + + +def restar(num1: float, num2: float) -> float: + """ + Realiza la resta de dos números + + Args: + n1 (float): Número 1 para restar + n2 (float): Número 2 a ser restado + + Returns: + float: La resta del Número 1 menos el Número 2 (n1-n2) + """ + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la resta de ambos. + + return num1 - num2 + + +def es_resultado_negativo(num1: float, num2: float) -> bool: + """Determina si el resultado de una operación entre num1 y num2 debe ser negativo.""" + # TODO: Realizar el desarrollo completo de esta función teniendo en cuenta la documentación y completándola también. + # Debe pasar las pruebas unitarias. + # Se trata de una función que os puede venir bien para utilizarla tanto en la función multiplicar, como en dividir. + # Ya que va a determinar si la multiplicación o división entre dos números debería ser de signo negativo o no. + num1_es_negativo = num1 < 0 + num2_es_negativo = num2 < 0 + + if num1_es_negativo != num2_es_negativo: + return True + else: + return False + +def multiplicar(num1: float, num2: float) -> int: + """ + Realiza la multiplicación ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la multiplicación. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de multiplicación de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la multiplicación con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 * 3.33, deberá convertirse en 5 * 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 * -5 = 25 + # 6. OBLIGATORIO usar un bucle for. + # 7. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + try: + es_negativo = es_resultado_negativo(num1, num2) + + num1 = abs(round(num1)) + num2 = abs(round(num2)) + + resultado = num1 + + for _ in range(num2-1): + resultado = resultado + num1 + + except Exception as e: + print(e) + + else: + if es_negativo: + resultado = -resultado + else: + resultado = abs(resultado) + return resultado + +def dividir(num1: float, num2: float) -> int: + """ + Realiza la división ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Dividendo. + num2 (float): Divisor. + + Returns: + int: Resultado de la división. + + Raises: + ZeroDivisionError: Si el divisor es cero. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de división de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la división con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 / 3.33, deberá convertirse en 5 / 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 / -5 = 1 + # 6. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + es_negativo = es_resultado_negativo(num1, num2) # Llamamos a la función para comprobar si es negativo o no + + num1 = abs(round(num1)) + num2 = abs(round(num2)) + + resultado = 0 + + if num2 == 0: + raise ZeroDivisionError + + if num2 > num1: + resultado = 0 + + elif num2 == num1: + resultado = 1 + + else: + resultado_temp = num1 + counter = 0 + + while resultado_temp >= 0: + resultado_temp = resultado_temp - num2 + counter += 1 + + resultado = counter - 1 + + # En caso que alguno de los dos números sea negativo, cambiaremos el resultado a negativo, pues un número positivo entre un número negativo, debe retonar un número negativo. + if es_negativo: + resultado = -resultado + + return resultado + +def potencia(num1: float, num2: float) -> int: + """ + Realiza la potencia entre el num 1 y num2 (num1**num2) + + Args: + num1 (float): Base. + num2 (float): Exponente. + + Returns: + int: Resultado de la potencia. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función y su documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. PREMISAS a tener en cuenta: + # - Cualquier número elevado a 0 da como resultado 1. + # - Para simplificar esta función, vamos a suponer que un número elevado a un + # exponente negativo siempre dará 0 (aunque en realidad no es así matemáticamente) + # 4. Utiliza la función de multiplicar para realizar los cálculos que te + # harán falta en esta función (RECUERDA que no puedes usar directamente los operadores + # de Python para la multiplicación y división). + # 5. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + try: + if num2 == 0: + resultado = 1 + elif num2 < 0: + resultado = 0 + else: + num1_abs = abs(round(num1)) + num2_abs = abs(round(num2)) + resultado = 0 + for _ in range(num2_abs): + multiplicacion = multiplicar(num1_abs, num1_abs) + resultado = resultado + multiplicacion + + if num2_abs % 2 != 0 and num1 < 0: + resultado = -resultado + + except Exception as e: + mostrar_error(6, e) + + else: + return resultado + +def pedir_entrada(msj: str) -> str: + """ + Pide al usuario una entrada, elimina espacios por delante y por detrás y la convierte a minúsculas. + + Args: + msj (str): Mensaje para solicitar la entrada. + + Returns: + str: Entrada del usuario. + """ + # TODO: El desarrollo de esta función está incompleto, debéis terminarla teniendo en cuenta la documentación + entrada = input(msj).strip().lower() + return entrada + + +def calcular_operacion(num1: float, num2: float, operador: str) -> float: + """ + Realiza la operación especificada entre num1 y num2 dependiendo del valor del operador. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + float: Resultado de la operación. + + Raises: + ZeroDivisionError: Si el divisor es cero. + """ + # TODO: El desarrollo de esta función está incompleto... completadla teniendo en cuenta la documentación + # y que debe realizar las llamadas adecuadas a las funciones ya creadas para realizar los distintos + # cálculos... sumar, restar, multiplicar, dividir y potencia. + # IMPORTANTE: Si hacemos caso a la documentación de esta función, NO debéis capturar la excepción + # ZeroDivisionError aquí, sino que hay que dejadla que se propague a la función llamante, realizar_calculo(), + # dónde se os indica cómo realizar la gestión de estos errores. + + if operador == "+": + resultado = sumar(num1, num2) + elif operador == "-": + resultado = restar(num1, num2) + elif operador == "x" or operador == "*": + resultado = multiplicar(num1, num2) + elif operador == "/" or operador == ":": + resultado = dividir(num1, num2) + # El Raises de ZeroDivisionError ya lo trae la "función dividir()", pues ahí en la documentación pide que se haga un Raise tambien. + # Asi que no he hecho otro Raise en esta funciíon "calcular_operacion()", pues al ya haber hecho un Raise lo capturará sin problemas "realizar_calculo()" + + elif operador == "**" or operador == "exp": + resultado = potencia(num1, num2) + + if resultado: + resultado = float(resultado) + + return resultado + + +def obtener_operaciones() -> str: + """ + Devuelve una cadena con la lista de operaciones disponibles en la calculadora. + + Returns: + (str): cadena de caracteres con la información de las operaciones disponibles. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + """ + Operaciones disponibles: + ce => Reiniciar resultado a 0 + decimales => Establecer decimales en resultado + cadena vacía + => Pregunta si desea salir + calculo => Iniciar cálculo secuencial + + => Suma + - => Resta + x o * => Multiplicación + / o : => División + ** o exp => Potencia + cancelar => volver sin actualizar resultado de la calculadora + cadena vacía + => volver actualizando resultado de la calculadora + """ + operaciones_disponibles = """Operaciones disponibles: + ce => Reiniciar resultado a 0 + decimales => Establecer decimales en resultado + cadena vacía + => Pregunta si desea salir + calculo => Iniciar cálculo secuencial + + => Suma + - => Resta + x o * => Multiplicación + / o : => División + ** o exp => Potencia + cancelar => volver sin actualizar resultado de la calculadora + cadena vacía + => volver actualizando resultado de la calculadora""" + + return operaciones_disponibles + + +def realizar_calculo(decimales: int, resultado_almacenado: float) -> float: + """ + Realiza una secuencia de cálculos solicitando números y operadores al usuario. + + Args: + decimales (int): Número de decimales para el resultado. + resultado_almacenado (float): Valor almacenado en la calculadora. + + Returns: + float: Resultado final del cálculo o None si se cancela. + + Note: + * Dentro de esta función el usuario puede realizar cálculos secuenciales, es decir, + comenzará introduciendo un número, después un operador, y otro número... a partir + de aquí sobre el resultado acumulado, introducirá operador y número para seguir + realizando cálculos (ver ejemplos en README.md de la tarea en el repositorio de GitHub). + * El usuario es guiado para introducir números y operadores secuencialmente + para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el + resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado + de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el + resultado almacenado de la calculadora. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + + operador = None + resultado = None + realizando_calculos = True + + print("\n## Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo ##\n") + + try: + + while realizando_calculos: + + if resultado == None: + entrada = pedir_entrada(f"\t (Cálculo = {0:.{decimales}f}) >> ") + else: + entrada = pedir_entrada(f"\t (Cálculo = {resultado:.{decimales}f}) >> ") + + if entrada == "cancelar": + print("Secuencia cancelada. Resultado almacenado sin cambios.") + realizando_calculos = False + + elif entrada == "": + return resultado + + elif entrada in OPERADORES: + operador = entrada + + else: + # TODO: este código funciona cuando solucionéis que reconozca las variables resultado_almacenado y decimales. + # Pero no gestiona los posibles tipos de Excepciones que se pueden producir: + # - ValueError que debe mostrar el error que está en la posición 2 de MENSAJES_ERROR. + # - ZeroDivisionError que debe mostrar el error que está en la posición 5 de MENSAJES_ERROR. + # - Exception que debe mostrar el error que está en la posición 6 de MENSAJES_ERROR. + if entrada == "resultado": + entrada = resultado_almacenado + + numero = float(entrada) + + if operador is not None: + + if resultado is None: + resultado = 0 + + resultado = round(calcular_operacion(resultado, numero, operador), decimales) + operador = None + + elif resultado is None: + resultado = numero + + else: + mostrar_error(3) + + except ValueError: + mostrar_error(2) + + except ZeroDivisionError: + mostrar_error(5) + + except Exception as e: + mostrar_error(6, e) + + else: + return resultado + + +def main(): + """ + Función principal de la calculadora. Gestiona la entrada del usuario y coordina las operaciones. + + Note: + El flujo del programa es el siguiente: + + 1. Inicia la calculadora mostrando el resultado almacenado por defecto (0.00). + + 2. El usuario ingresa un comando, que puede ser: + - "lista" para ver todas las operaciones disponibles. + - "ce" para reiniciar el resultado almacenado a 0. + - "decimales " para establecer el número de decimales mostrados en el resultado. + - "calculo" para iniciar una secuencia de cálculo paso a paso. + - Una entrada vacía y pulsa la tecla para salir de la calculadora. + + 3. Según el comando ingresado: + - El programa realiza la operación o ejecuta la acción indicada. + - Al ingresar "calculo": + * El usuario es guiado para introducir números y operadores secuencialmente para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el resultado almacenado de la calculadora. + + 4. La calculadora sigue ejecutándose hasta que el usuario confirma la salida al ingresar una entrada vacía y pulsar . + + 5. Finalmente, se limpia la pantalla, el programa se despide con el mensaje "\n\nBye, bye...\n\n" y termina. + """ + # TODO: Corrige los errores y haz que el main funcione correctamente... + + print("Menú") + print("1. Realizar un cálculo secuencial.") + print("2. Lista de operaciones disponibles para el cálculo.") + print("3. Reiniciar resultado (CE).") + print("4. Configurar número de decimales.") + print("5. Salir.\n") + + option = input("~> ") + + decimales = 2 + resultado = 0.0 + desea_salir = False + + while not desea_salir: + limpiar_pantalla() + print("### CALCULADORA ###\n -----------\n") + + if resultado == None: + entrada = pedir_entrada(f"Operación (RES => {0:.{decimales}f}) >> ") + else: + entrada = pedir_entrada(f"Operación (RES => {resultado:.{decimales}f}) >> ") + + if entrada == "": + salir_opcion = pedir_entrada("¿Desea salir de la calculadora? (s/n) ") + if salir_opcion == "s" or salir_opcion == "si": + desea_salir = True + + elif entrada == "lista": + lista_operaciones = obtener_operaciones() + print(lista_operaciones) + pausa() + + elif entrada == "ce": + resultado = 0.0 + print("Resultado reiniciado a 0.") + pausa() + + elif entrada.startswith("decimales"): + # Extraemos las posiciones decimales y las convertimos a un valor entero + try: + decimales = int(str(entrada.split(' ')[1])) + print(f"Decimales configurados a {decimales}.") + pausa() + except IndexError: + mostrar_error(1) + + elif entrada == "calculo": + resultado = realizar_calculo(decimales, resultado) + pausa() + + else: + mostrar_error(4) + pausa() + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/daw1b_calculadora/inda_calculadora_alumnos.py b/daw1b_calculadora/inda_calculadora_alumnos.py new file mode 100644 index 0000000..0ea5dca --- /dev/null +++ b/daw1b_calculadora/inda_calculadora_alumnos.py @@ -0,0 +1,401 @@ +import os + + + +# TODO: ATENCIÓN!!! +# 1. Importar los paquetes necesarios +# 2. Usar la función mostrar_error para imprimir los errores por consola. +# 3. Los comentarios TODO os ayudan a resolver cada apartado de esta prueba. +# 4. CADA función SOLO puede tener una instrucción return. +# 5. En test_calculadora_alumnos.py crear el test unitario para la función es_resultado_negativo y hacer que todos los test unitarios se cumplan. + + + +# Mensajes de error predefinidos +MENSAJES_ERROR = ( + "Problemas al intentar limpiar la pantalla {error}", + "Error al configurar los decimales. Formato: decimales .", + "Entrada no válida. Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo.", + "Error: Introduzca un operador antes de otro número.", + "Comando no reconocido. Escriba 'lista' para ver las operaciones disponibles.", + "Error: no es posible la división por 0! Introduzca otro valor diferente a 0...", + "Se produjo un error: {error}" +) + +# Operadores soportados por la calculadora +OPERADORES = '+', '-', 'x' '*', '/' ':', '**' 'exp' +# TODO: Ayuda: incluye en esta constante los símbolos que reconocerá la aplicación para el cálculo de las operaciones: +# '+' para la suma. +# '-' para la resta. +# 'x' o '*' para la multiplicación. +# '/' o ':' para la división. +# '**' o 'exp' para la potencia. + + + + +def limpiar_pantalla(): + """ + Limpia la consola según el sistema operativo. + """ + # TODO: El desarrollo de esta función está incompleto y con errores. + try: + if os.name == "posix": + os.system('clear') + else: + os.system('cls') + # Otra forma de expresar la misma instrucción sería la siguiente: + # if os.name = posix: + # os.system(clear) + # else: + # os.system(cls) + except Exception as e: + mostrar_error(f"\n*ERROR* Problemas al mostrar error!\n{e}\n") + + +def pausa(): + """ + Pausa la ejecución del programa hasta que se pulse ENTER... "\nPresione ENTER para continuar..." + """ + # TODO: Desarrollar esta función según su documentación. + int("\nPresione Enter para continuar...") + + +def mostrar_error(indice_error: int, msj_error = None): + """ + Muestra un mensaje de error en la consola. + + Args: + indice_error (int): Índice del mensaje de error en MENSAJES_ERROR. + msj_error (str, opcional): Texto adicional para personalizar el mensaje de error. + """ + # TODO: + # 1. Corrige el error que existe a la hora de acceder a los mensajes de error que están en la constante + # MENSAJES_ERROR. A los elementos de una tupla se accede igual que a los caracteres de una + # cadena de caracteres. + # 2. Completa el código de esta función para que controle específicamente las excepciones IndexError y + # muestre el mensaje: "\n*ERROR* Mensaje de error no definido.\n" + # 3. También se pide que se controle cualquier otra excepción que se pueda producir y muestre el mensaje: + # "\n*ERROR* Problemas al mostrar error!\n{e}\n" + # 4. En esta función los mensajes de error deben mostrarse con print. + MENSAJES_ERROR + if msj_error != None: + print(f"\n*ERROR* {MENSAJES_ERROR.format(error = msj_error)}\n") + else: + print(f"\n*ERROR* {MENSAJES_ERROR}\n") + + + +def sumar(num1: float, num2: float) -> bool: + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la suma de ambos. + """ + Realiza la suma ENTERA de dos números usando solo sumas. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la suma. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + resultado = 0 + numero1, numero2 = int(num1), int(num2) + for _ in range(numero2): + resultado += numero1 + + + +def restar(): + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la resta de ambos. + """ + Realiza la resta ENTERA de dos números usando solo restas. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la resta. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + + + +def es_resultado_negativo(num1: float, num2: float) -> bool: + """ + Determina si el resultado de una operación entre num1 y num2 debe ser negativo. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado negativo dependiendo de los signos matemáticos. + """ + # TODO: Realizar el desarrollo completo de esta función teniendo en cuenta la documentación y completándola también. + # Debe pasar las pruebas unitarias. + # Se trata de una función que os puede venir bien para utilizarla tanto en la función multiplicar, como en dividir. + # Ya que va a determinar si la multiplicación o división entre dos números debería ser de signo negativo o no. + + return (num1 < 0) != (num2 < 0) + + +def multiplicar(num1: float, num2: float) -> bool: + """ + Realiza la multiplicación ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la multiplicación. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de multiplicación de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la multiplicación con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 * 3.33, deberá convertirse en 5 * 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 * -5 = 25 + # 6. OBLIGATORIO usar un bucle for. + # 7. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + positivo = (numero1 > 0) == (numero2 > 0) + numero1, numero2 = int(num1), int(num2) + resultado = 0 + for _ in range(numero2): + resultado += numero1 + + return resultado if positivo else -resultado + + +def dividir(): + """ + Realiza la división ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Dividendo. + num2 (float): Divisor. + + Returns: + int: Resultado de la división. + + Raises: + ZeroDivisionError: Si el divisor es cero. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de división de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la división con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 / 3.33, deberá convertirse en 5 / 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 / -5 = 1 + # 6. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + dividendo, divisor = int(dividendo), int(divisor) + if divisor == 0: + raise ZeroDivisionError("El divisor no puede ser cero.") + + resultado = 0 + positivo = (dividendo > 0) == (divisor > 0) + dividendo, divisor = abs(dividendo), abs(divisor) + + while dividendo >= divisor: + dividendo -= divisor + resultado += 1 + + return resultado if positivo else -resultado + + +def potencia(base: float, exponente: float) -> bool: + """ + Realiza la potencia ENTERA de dos números usando solo la función multiplicación que hemos realizado + + Args: + num1 (float): Base. + num2 (float): Exponente. + + Returns: + int: Resultado de la potencia. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función y su documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. PREMISAS a tener en cuenta: + # - Cualquier número elevado a 0 da como resultado 1. + # - Para simplificar esta función, vamos a suponer que un número elevado a un + # exponente negativo siempre dará 0 (aunque en realidad no es así matemáticamente) + # 4. Utiliza la función de multiplicar para realizar los cálculos que te + # harán falta en esta función (RECUERDA que no puedes usar directamente los operadores + # de Python para la multiplicación y división). + # 5. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + base, exponente = int(base), int(exponente) + if exponente == 0: + return 1 + if exponente < 0: + return 0 + + resultado = 1 + for _ in range(exponente): + resultado = multiplicar(resultado, base) + + return resultado + +def pedir_entrada(msj: str) -> str: + """ + Pide al usuario una entrada, elimina espacios por delante y por detrás y la convierte a minúsculas. + + Args: + msj (str): Mensaje para solicitar la entrada. + + Returns: + str: Entrada del usuario. + """ + # TODO: El desarrollo de esta función está incompleto, debéis terminarla teniendo en cuenta la documentación + entrada = entrada.upper() + return input(msj) + + +def obtener_operaciones(num1, num2, operador) -> str: + """ + Devuelve una cadena con la lista de operaciones disponibles en la calculadora. + + Returns: + (str): cadena de caracteres con la información de las operaciones disponibles. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + """ + Operaciones disponibles: + ce => Reiniciar resultado a 0 + decimales => Establecer decimales en resultado + cadena vacía + => Pregunta si desea salir + calculo => Iniciar cálculo secuencial + + => Suma + - => Resta + x o * => Multiplicación + / o : => División + ** o exp => Potencia + cancelar => vovler sin actualizar resultado de la calculadora + cadena vacía + => volver actualizando resultado de la calculadora + """ + if operador == "+": + return num1 + num2 + elif operador == "-": + return num1 - num2 + elif operador in ["*", "x"]: + return multiplicar(num1, num2) + elif operador in ["/", ":"]: + return dividir(num1, num2) + elif operador in ["**", "exp"]: + return potencia(num1, num2) + else: + raise ValueError("Operador no válido") + + +def realizar_calculo(): + """ + Realiza una secuencia de cálculos solicitando números y operadores al usuario. + + Args: + decimales (int): Número de decimales para el resultado. + resultado_almacenado (float): Valor almacenado en la calculadora. + + Returns: + float: Resultado final del cálculo o None si se cancela. + + Note: + * Dentro de esta función el usuario puede realizar cálculos secuenciales, es decir, + comenzará introduciendo un número, después un operador, y otro número... a partir + de aquí sobre el resultado acumulado, introducirá operador y número para seguir + realizando cálculos (ver ejemplos en README.md de la tarea en el repositorio de GitHub). + * El usuario es guiado para introducir números y operadores secuencialmente + para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el + resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado + de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el + resultado almacenado de la calculadora. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + + resultado = 0 + continuar = True + while continuar: + try: + entrada = input(f"(Cálculo = {resultado}) >> ") + if entrada.lower() in ["salir", "cancelar"]: + continuar = False + elif entrada == "": + print(f"Resultado final: {resultado}") + continuar = False + elif entrada == "resultado": + print(f"Resultado actual: {resultado}") + else: + partes = entrada.split() + if len(partes) != 2: + raise ValueError("Entrada no válida. Debe contener un número y un operador.") + + num, operador = partes + num = float(num) + resultado = obtener_operaciones(resultado, num, operador) + except Exception as e: + mostrar_error(e) + + +def main(): + """ + Función principal de la calculadora. Gestiona la entrada del usuario y coordina las operaciones. + + Note: + El flujo del programa es el siguiente: + + 1. Inicia la calculadora mostrando el resultado almacenado por defecto (0.00). + + 2. El usuario ingresa un comando, que puede ser: + - "lista" para ver todas las operaciones disponibles. + - "ce" para reiniciar el resultado almacenado a 0. + - "decimales " para establecer el número de decimales mostrados en el resultado. + - "calculo" para iniciar una secuencia de cálculo paso a paso. + - Una entrada vacía y pulsa la tecla para salir de la calculadora. + + 3. Según el comando ingresado: + - El programa realiza la operación o ejecuta la acción indicada. + - Al ingresar "calculo": + * El usuario es guiado para introducir números y operadores secuencialmente para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el resultado almacenado de la calculadora. + + 4. La calculadora sigue ejecutándose hasta que el usuario confirma la salida al ingresar una entrada vacía y pulsar . + + 5. Finalmente, se limpia la pantalla, el programa se despide con el mensaje "\n\nBye, bye...\n\n" y termina. + """ + # TODO: Corrige los errores y haz que el main funcione correctamente... + """Función principal que organiza el flujo de la calculadora.""" + + limpiar_pantalla() + print("Bienvenido a la calculadora básica en Python.") + realizar_calculo() + pausa() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/daw1b_calculadora/jangel_calculadora_alumnos.py b/daw1b_calculadora/jangel_calculadora_alumnos.py new file mode 100644 index 0000000..f690111 --- /dev/null +++ b/daw1b_calculadora/jangel_calculadora_alumnos.py @@ -0,0 +1,413 @@ +# TODO: ATENCIÓN!!! +# 1. Importar los paquetes necesarios +# 2. Usar la función mostrar_error para imprimir los errores por consola. +# 3. Los comentarios TODO os ayudan a resolver cada apartado de esta prueba. +# 4. CADA función SOLO puede tener una instrucción return. +# 5. En test_calculadora_alumnos.py crear el test unitario para la función es_resultado_negativo y hacer que todos los test unitarios se cumplan. +import os +import time + + +# Mensajes de error predefinidos +MENSAJES_ERROR = ( + "Problemas al intentar limpiar la pantalla {error}", + "Error al configurar los decimales. Formato: decimales .", + "Entrada no válida. Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo.", + "Error: Introduzca un operador antes de otro número.", + "Comando no reconocido. Escriba 'lista' para ver las operaciones disponibles.", + "Error: no es posible la división por 0! Introduzca otro valor diferente a 0...", + "Se produjo un error: {error}" +) + +# Operadores soportados por la calculadora +OPERADORES = ( +# TODO: Ayuda: incluye en esta constante los símbolos que reconocerá la aplicación para el cálculo de las operaciones: +# '+' para la suma. +# '-' para la resta. +# 'x' o '*' para la multiplicación. +# '/' o ':' para la división. +# '**' o 'exp' para la potencia. +"+" +"-" +"x", "*" +"/", ":" +"**", "exp" +) + + +def limpiar_pantalla(): + """ + Limpia la consola según el sistema operativo. + """ + # TODO: El desarrollo de esta función está incompleto y con errores. + try: + os.system("clear" if os.name == "posix" else "cls") + # Otra forma de expresar la misma instrucción sería la siguiente: + # if os.name = posix: + # os.system(clear) + # else: + # os.system(cls) + except Exception as e: + mostrar_error(f"Problemas al intentar limpiar la pantalla: {e}") + + + +def pausa(tecla_enter = False): + if tecla_enter == False: + input("\nPresione ENTER para continuar...") + """ + Pausa la ejecución del programa hasta que se pulse ENTER... "\nPresione ENTER para continuar..." + """ + # TODO: Desarrollar esta función según su documentación. + + +def mostrar_error(indice_error: int, msj_error = None): + """ + Muestra un mensaje de error en la consola. + + Args: + indice_error (int): Índice del mensaje de error en MENSAJES_ERROR. + msj_error (str, opcional): Texto adicional para personalizar el mensaje de error. + """ + # TODO: + # 1. Corrige el error que existe a la hora de acceder a los mensajes de error que están en la constante + # MENSAJES_ERROR. A los elementos de una tupla se accede igual que a los caracteres de una + # cadena de caracteres. + # 2. Completa el código de esta función para que controle específicamente las excepciones IndexError y + # muestre el mensaje: "\n*ERROR* Mensaje de error no definido.\n" + # 3. También se pide que se controle cualquier otra excepción que se pueda producir y muestre el mensaje: + # "\n*ERROR* Problemas al mostrar error!\n{e}\n" + # 4. En esta función los mensajes de error deben mostrarse con print. + if msj_error != None: + print(f"\n*ERROR* {MENSAJES_ERROR.format(error = msj_error)}\n") + else: + print(f"\n*ERROR* {MENSAJES_ERROR}\n") + + +def sumar(num1: float, num2: float) -> int: + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la suma de ambos. + num1 = int("{:.0f}".format(num1)) + num2 = int("{:.0f}".format(num2)) + resultado = num1 + num2 + return resultado + + +def restar(num1: float, num2: float) -> int: + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la resta de ambos. + num1 = int("{:.0f}".format(num1)) + num2 = int("{:.0f}".format(num2)) + resultado = num1 - num2 + return resultado + + +def es_resultado_negativo(num1: float, num2: float) -> bool: + """Determina si el resultado de una operación entre num1 y num2 debe ser negativo.""" + # TODO: Realizar el desarrollo completo de esta función teniendo en cuenta la documentación y completándola también. + # Debe pasar las pruebas unitarias. + # Se trata de una función que os puede venir bien para utilizarla tanto en la función multiplicar, como en dividir. + # Ya que va a determinar si la multiplicación o división entre dos números debería ser de signo negativo o no. + if num1.starwith("-") or num2.starwith("-"): + return True + + + + +def multiplicar(num1: float, num2: float) -> int: + """ + Realiza la multiplicación ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la multiplicación. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + num1 = int("{:.0f}".format(num1)) + num2 = int("{:.0f}".format(num2)) + + resultado = 0 + for i in range (num2): + resultado += num1 + + return resultado + + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de multiplicación de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la multiplicación con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 * 3.33, deberá convertirse en 5 * 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 * -5 = 25 + # 6. OBLIGATORIO usar un bucle for. + # 7. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + + +def dividir(): + """ + Realiza la división ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Dividendo. + num2 (float): Divisor. + + Returns: + int: Resultado de la división. + + Raises: + ZeroDivisionError: Si el divisor es cero. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de división de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la división con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 / 3.33, deberá convertirse en 5 / 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 / -5 = 1 + # 6. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + num1 = int("{:.0f}".format(num1)) + num2 = int("{:.0f}".format(num2)) + division = 0 + resultado = 0 + while num2 < num1: + for i in range (num2): + num1 = num1 - num2 + resultado = num1 + division += 1 + return resultado + +def potencia(num1: float, num2: float) -> int: + # TODO: + # 1. Realizar el desarrollo completo de esta función y su documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. PREMISAS a tener en cuenta: + # - Cualquier número elevado a 0 da como resultado 1. + # - Para simplificar esta función, vamos a suponer que un número elevado a un + # exponente negativo siempre dará 0 (aunque en realidad no es así matemáticamente) + # 4. Utiliza la función de multiplicar para realizar los cálculos que te + # harán falta en esta función (RECUERDA que no puedes usar directamente los operadores + # de Python para la multiplicación y división). + # 5. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + num1 = int("{:.0f}".format(num1)) + num2 = int("{:.0f}".format(num2)) + + +def pedir_entrada(msj: str) -> str: + """ + Pide al usuario una entrada, elimina espacios por delante y por detrás y la convierte a minúsculas. + + Args: + msj (str): Mensaje para solicitar la entrada. + + Returns: + str: Entrada del usuario. + """ + # TODO: El desarrollo de esta función está incompleto, debéis terminarla teniendo en cuenta la documentación + return input(msj.strip().lower()) + + +def calcular_operacion(num1: float, num2: float, operador: str) -> float: + """ + Realiza la operación especificada entre num1 y num2 dependiendo del valor del operador. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + float: Resultado de la operación. + + Raises: + ZeroDivisionError: Si el divisor es cero. + """ + if operador == "-": + resultado = restar(num1,num2) + elif operador == "+": + resultado = sumar(num1,num2) + elif operador == "x" or operador == "*": + resultado = multiplicar(num1,num2) + elif operador == "/" or operador == ":": + resultado = dividir(num1,num2) + if num2 == 0: + raise ZeroDivisionError + elif operador == "**" or operador == "^": + resultado = potencia(num1,num2) + + # TODO: El desarrollo de esta función está incompleto... completadla teniendo en cuenta la documentación + # y que debe realizar las llamadas adecuadas a las funciones ya creadas para realizar los distintos + # cálculos... sumar, restar, multiplicar, dividir y potencia. + # IMPORTANTE: Si hacemos caso a la documentación de esta función, NO debéis capturar la excepción + # ZeroDivisionError aquí, sino que hay que dejadla que se propague a la función llamante, realizar_calculo(), + # dónde se os indica cómo realizar la gestión de estos errores. + + return resultado + + + +def obtener_operaciones() -> str: + """ + Devuelve una cadena con la lista de operaciones disponibles en la calculadora. + + Returns: + (str): cadena de caracteres con la información de las operaciones disponibles. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + LISTA = ( + "Operaciones disponibles:" + "ce => Reiniciar resultado a 0" + "decimales => Establecer decimales en resultado" + "cadena vacía + => Pregunta si desea salir" + "calculo => Iniciar cálculo secuencial" + "+ => Suma" + "- => Resta" + "x o * => Multiplicación" + "/ o : => División" + "** o exp => Potencia" + "cancelar => vovler sin actualizar resultado de la calculadora" + "cadena vacía + => volver actualizando resultado de la calculadora" + ) + return LISTA + +def realizar_calculo(): + """ + Realiza una secuencia de cálculos solicitando números y operadores al usuario. + + Args: + decimales (int): Número de decimales para el resultado. + resultado_almacenado (float): Valor almacenado en la calculadora. + + Returns: + float: Resultado final del cálculo o None si se cancela. + + Note: + * Dentro de esta función el usuario puede realizar cálculos secuenciales, es decir, + comenzará introduciendo un número, después un operador, y otro número... a partir + de aquí sobre el resultado acumulado, introducirá operador y número para seguir + realizando cálculos (ver ejemplos en README.md de la tarea en el repositorio de GitHub). + * El usuario es guiado para introducir números y operadores secuencialmente + para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el + resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado + de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el + resultado almacenado de la calculadora. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + + operador = None + resultado = None + realizando_calculos = True + + print("\n## Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo ##\n") + + while realizando_calculos: + entrada = pedir_entrada(f"\t (Cálculo = resultado) >> ") + + if entrada == "cancelar": + entrada = pedir_entrada(f"\t (Cálculo = resultado) >> ") + + elif entrada == "": + salir = input("Desea salir del programa? s/n") + + + elif entrada in OPERADORES: + operador = pedir_entrada(f"\t >>>") + + else: + # TODO: este código funciona cuando solucionéis que reconozca las variables resultado_almacenado y decimales. + # Pero no gestiona los posibles tipos de Excepciones que se pueden producir: + # - ValueError que debe mostrar el error que está en la posición 2 de MENSAJES_ERROR. + # - ZeroDivisionError que debe mostrar el error que está en la posición 5 de MENSAJES_ERROR. + # - Exception que debe mostrar el error que está en la posición 6 de MENSAJES_ERROR. + if entrada == "resultado": + entrada = resultado_almacenado + + try: + numero = float(entrada) + + if operador is not None: + if resultado is None: + resultado = 0 + resultado = round(calcular_operacion(resultado, numero, operador), decimales) + operador = None + + elif resultado is None: + resultado = numero + + else: + mostrar_error(3) + except: + + + +def main(): + """ + Función principal de la calculadora. Gestiona la entrada del usuario y coordina las operaciones. + + Note: + El flujo del programa es el siguiente: + + 1. Inicia la calculadora mostrando el resultado almacenado por defecto (0.00). + + 2. El usuario ingresa un comando, que puede ser: + - "lista" para ver todas las operaciones disponibles. + - "ce" para reiniciar el resultado almacenado a 0. + - "decimales " para establecer el número de decimales mostrados en el resultado. + - "calculo" para iniciar una secuencia de cálculo paso a paso. + - Una entrada vacía y pulsa la tecla para salir de la calculadora. + + 3. Según el comando ingresado: + - El programa realiza la operación o ejecuta la acción indicada. + - Al ingresar "calculo": + * El usuario es guiado para introducir números y operadores secuencialmente para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el resultado almacenado de la calculadora. + + 4. La calculadora sigue ejecutándose hasta que el usuario confirma la salida al ingresar una entrada vacía y pulsar . + + 5. Finalmente, se limpia la pantalla, el programa se despide con el mensaje "\n\nBye, bye...\n\n" y termina. + """ + # TODO: Corrige los errores y haz que el main funcione correctamente... + + decimales = 2 + resultado = 0.0 + + while not desea_salir: + + pedir_entrada(f"Operación (RES => resultado) >> ") + + if entrada == "": + pedir_entrada("¿Desea salir de la calculadora? (s/n) ") + + elif entrada == "lista": + obtener_operaciones + + elif entrada == "ce": + + + elif entrada.startswith("decimales"): + # Extraemos las posiciones decimales y las convertimos a un valor entero + decimales = str(entrada.split()[1]) + print(f"Decimales configurados a {decimales}.") + + elif entrada == "calculo": + realizar_calculo(decimales, resultado) + + else: + mostrar_error +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/daw1b_calculadora/jantonio_calculadora_alumnos.py b/daw1b_calculadora/jantonio_calculadora_alumnos.py new file mode 100644 index 0000000..3756e08 --- /dev/null +++ b/daw1b_calculadora/jantonio_calculadora_alumnos.py @@ -0,0 +1,423 @@ +# TODO: ATENCIÓN!!! +# 1. Importar los paquetes necesarios +# 2. Usar la función mostrar_error para imprimir los errores por consola. +# 3. Los comentarios TODO os ayudan a resolver cada apartado de esta prueba. +# 4. CADA función SOLO puede tener una instrucción return. +# 5. En test_calculadora_alumnos.py crear el test unitario para la función es_resultado_negativo y hacer que todos los test unitarios se cumplan. + +import os +import time + +# Mensajes de error predefinidos +MENSAJES_ERROR = ( + "Problemas al intentar limpiar la pantalla {error}", + "Error al configurar los decimales. Formato: decimales .", + "Entrada no válida. Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo.", + "Error: Introduzca un operador antes de otro número.", + "Comando no reconocido. Escriba 'lista' para ver las operaciones disponibles.", + "Error: no es posible la división por 0! Introduzca otro valor diferente a 0...", + "Se produjo un error: {error}" +) + +# Operadores soportados por la calculadora +OPERADORES = ("+","-","*","x","/",":","**","exp") +# TODO: Ayuda: incluye en esta constante los símbolos que reconocerá la aplicación para el cálculo de las operaciones: +# '+' para la suma. +# '-' para la resta. +# 'x' o '*' para la multiplicación. +# '/' o ':' para la división. +# '**' o 'exp' para la potencia. + + + +def limpiar_pantalla(): + """ + Limpia la consola según el sistema operativo. + """ + # TODO: El desarrollo de esta función está incompleto y con errores. + try: + # Otra forma de expresar la misma instrucción sería la siguiente: + # if os.name = posix: + # os.system(clear) + # else: + # os.system(cls) + if os.name == "posix": + os.system("clear") + else: + os.system("cls") + except Exception as e: + return f"*ERROR {e}* Fallo al limpiar consola." + + + + +def pausa(tiempo = 2): + """ + Pausa la ejecución del programa hasta que se pulse ENTER... "\nPresione ENTER para continuar..." + """ + # TODO: Desarrollar esta función según su documentación. + print("\nPresione ENTER para continuar...") + time.sleep(tiempo) + +def mostrar_error(indice_error: int, msj_error = None): + """ + Muestra un mensaje de error en la consola. + + Args: + indice_error (int): Índice del mensaje de error en MENSAJES_ERROR. + msj_error (str, opcional): Texto adicional para personalizar el mensaje de error. + """ + # TODO: + # 1. Corrige el error que existe a la hora de acceder a los mensajes de error que están en la constante + # MENSAJES_ERROR. A los elementos de una tupla se accede igual que a los caracteres de una + # cadena de caracteres. + # 2. Completa el código de esta función para que controle específicamente las excepciones IndexError y + # muestre el mensaje: "\n*ERROR* Mensaje de error no definido.\n" + # 3. También se pide que se controle cualquier otra excepción que se pueda producir y muestre el mensaje: + # "\n*ERROR* Problemas al mostrar error!\n{e}\n" + # 4. En esta función los mensajes de error deben mostrarse con print. + if msj_error != None: + print(f"\n*ERROR* {MENSAJES_ERROR.format(error = msj_error)}\n") + else: + print(f"\n*ERROR* {MENSAJES_ERROR}\n") + + +def sumar(num1: float, num2:float)-> int: + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la suma de ambos. + """ + Devuelve el resultado de la suma entre 2 numeros. + + Args: + num1 (float): numero 1 a la suma entre 2 numeros. + num2 (float): numero 2 a la suma entre 2 numeros. + """ + suma = num1 + num2 + return round(suma) + + +def restar(num1: float, num2:float)-> int: + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la resta de ambos. + """ + Devuelve el resultado de la resta entre 2 numeros. + + Args: + num1 (float): numero 1 a la resta entre 2 numeros. + num2 (float): numero 2 a la resta entre 2 numeros. + """ + resta = num1 - num2 + return round(resta) + + +def es_resultado_negativo(num1: float, num2: float) -> bool: + """Determina si el resultado de una operación entre num1 y num2 debe ser negativo.""" + # TODO: Realizar el desarrollo completo de esta función teniendo en cuenta la documentación y completándola también. + # Debe pasar las pruebas unitarias. + # Se trata de una función que os puede venir bien para utilizarla tanto en la función multiplicar, como en dividir. + # Ya que va a determinar si la multiplicación o división entre dos números debería ser de signo negativo o no. + pass + + + +def multiplicar(num1: float, num2:float)-> int: + """ + Realiza la multiplicación ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la multiplicación. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de multiplicación de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la multiplicación con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 * 3.33, deberá convertirse en 5 * 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 * -5 = 25 + # 6. OBLIGATORIO usar un bucle for. + # 7. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + multiplicacion = 0 + for i in range(round(num2)): + multiplicacion += round(num1) + i += 1 + return multiplicacion + + +def dividir(num1: float, num2:float)-> int: + """ + Realiza la división ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Dividendo. + num2 (float): Divisor. + + Returns: + int: Resultado de la división. + + Raises: + ZeroDivisionError: Si el divisor es cero. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de división de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la división con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 / 3.33, deberá convertirse en 5 / 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 / -5 = 1 + # 6. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + pass + +def potencia(): + # TODO: + # 1. Realizar el desarrollo completo de esta función y su documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. PREMISAS a tener en cuenta: + # - Cualquier número elevado a 0 da como resultado 1. + # - Para simplificar esta función, vamos a suponer que un número elevado a un + # exponente negativo siempre dará 0 (aunque en realidad no es así matemáticamente) + # 4. Utiliza la función de multiplicar para realizar los cálculos que te + # harán falta en esta función (RECUERDA que no puedes usar directamente los operadores + # de Python para la multiplicación y división). + # 5. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + pass + +def pedir_entrada(msj: str) -> str: + """ + Pide al usuario una entrada, elimina espacios por delante y por detrás y la convierte a minúsculas. + + Args: + msj (str): Mensaje para solicitar la entrada. + + Returns: + str: Entrada del usuario. + """ + # TODO: El desarrollo de esta función está incompleto, debéis terminarla teniendo en cuenta la documentación + return input(msj).strip().lower() + + +def calcular_operacion(numero: float, operador: str, resultado: float) -> float: + """ + Realiza la operación especificada entre num1 y num2 dependiendo del valor del operador. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + float: Resultado de la operación. + + Raises: + ZeroDivisionError: Si el divisor es cero. + """ + # TODO: El desarrollo de esta función está incompleto... completadla teniendo en cuenta la documentación + # y que debe realizar las llamadas adecuadas a las funciones ya creadas para realizar los distintos + # cálculos... sumar, restar, multiplicar, dividir y potencia. + # IMPORTANTE: Si hacemos caso a la documentación de esta función, NO debéis capturar la excepción + # ZeroDivisionError aquí, sino que hay que dejadla que se propague a la función llamante, realizar_calculo(), + # dónde se os indica cómo realizar la gestión de estos errores. + num1 = 0 + num2 = 0 + + if num1 == 0: + num1 = numero + else: + num2 = numero + + if operador == "+": + sumar(num1, num2) + if operador == "-": + restar(num1, num2) + if operador == "*" or operador == "x": + multiplicar(num1, num2) + if operador == "/" or operador == ":": + dividir(num1, num2) + if operador == "exp" or operador == "**": + potencia() + + return float(resultado) + + + +def obtener_operaciones() -> str: + """ + Devuelve una cadena con la lista de operaciones disponibles en la calculadora. + + Returns: + (str): cadena de caracteres con la información de las operaciones disponibles. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + """ + Operaciones disponibles: + ce => Reiniciar resultado a 0 + decimales => Establecer decimales en resultado + cadena vacía + => Pregunta si desea salir + calculo => Iniciar cálculo secuencial + + => Suma + - => Resta + x o * => Multiplicación + / o : => División + ** o exp => Potencia + cancelar => vovler sin actualizar resultado de la calculadora + cadena vacía + => volver actualizando resultado de la calculadora + """ + operaciones = ("Operaciones disponibles:\n ce => Reiniciar resultado a 0\n decimales => Establecer decimales en resultado\n cadena vacía + => Pregunta si desea salir" + "\n calculo => Iniciar cálculo secuencial\n + => Suma\n - => Resta\n x o * => Multiplicación" + "\n / o : => División\n ** o exp => Potencia\n cancelar => vovler sin actualizar resultado de la calculadora\n cadena vacía + => volver actualizando resultado de la calculadora") + + return operaciones + +def realizar_calculo(decimales: int, resultado_almacenado: int): + """ + Realiza una secuencia de cálculos solicitando números y operadores al usuario. + + Args: + decimales (int): Número de decimales para el resultado. + resultado_almacenado (float): Valor almacenado en la calculadora. + + Returns: + float: Resultado final del cálculo o None si se cancela. + + Note: + * Dentro de esta función el usuario puede realizar cálculos secuenciales, es decir, + comenzará introduciendo un número, después un operador, y otro número... a partir + de aquí sobre el resultado acumulado, introducirá operador y número para seguir + realizando cálculos (ver ejemplos en README.md de la tarea en el repositorio de GitHub). + * El usuario es guiado para introducir números y operadores secuencialmente + para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el + resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado + de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el + resultado almacenado de la calculadora. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + + operador = None + resultado = None + realizando_calculos = True + + print("\n## Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo ##\n") + + while realizando_calculos: + entrada = pedir_entrada(f"\t (Cálculo = {resultado}) >> ") + if entrada == "cancelar": + print("Secuencia cancelada. Resultado almacenado sin cambios.") + pausa() + + elif entrada == "": + pedir_entrada("¿Desea salir de la calculadora? (s/n) ") + limpiar_pantalla() + if entrada == "s": + print("Bye bye...") + realizando_calculos = False + + elif entrada in OPERADORES: + operador = OPERADORES.index(entrada) + + else: + # TODO: este código funciona cuando solucionéis que reconozca las variables resultado_almacenado y decimales. + # Pero no gestiona los posibles tipos de Excepciones que se pueden producir: + # - ValueError que debe mostrar el error que está en la posición 2 de MENSAJES_ERROR. + # - ZeroDivisionError que debe mostrar el error que está en la posición 5 de MENSAJES_ERROR. + # - Exception que debe mostrar el error que está en la posición 6 de MENSAJES_ERROR. + if entrada == "resultado": + entrada = resultado_almacenado + + try: + numero = float(entrada) + + if operador is not None: + if resultado is None: + resultado = 0 + raise mostrar_error(2) + resultado = round(calcular_operacion(resultado, numero, operador), decimales) + operador = None + + elif resultado is None: + resultado = numero + + else: + mostrar_error(3) + except ValueError: + mostrar_error(6) + + + +def main(): + """ + Función principal de la calculadora. Gestiona la entrada del usuario y coordina las operaciones. + + Note: + El flujo del programa es el siguiente: + + 1. Inicia la calculadora mostrando el resultado almacenado por defecto (0.00). + + 2. El usuario ingresa un comando, que puede ser: + - "lista" para ver todas las operaciones disponibles. + - "ce" para reiniciar el resultado almacenado a 0. + - "decimales " para establecer el número de decimales mostrados en el resultado. + - "calculo" para iniciar una secuencia de cálculo paso a paso. + - Una entrada vacía y pulsa la tecla para salir de la calculadora. + + 3. Según el comando ingresado: + - El programa realiza la operación o ejecuta la acción indicada. + - Al ingresar "calculo": + * El usuario es guiado para introducir números y operadores secuencialmente para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el resultado almacenado de la calculadora. + + 4. La calculadora sigue ejecutándose hasta que el usuario confirma la salida al ingresar una entrada vacía y pulsar . + + 5. Finalmente, se limpia la pantalla, el programa se despide con el mensaje "\n\nBye, bye...\n\n" y termina. + """ + # TODO: Corrige los errores y haz que el main funcione correctamente... + + decimales = 2 + resultado = 0.0 + desea_salir = False + while not desea_salir: + + entrada = pedir_entrada(f"Operación (RES => {resultado}) >> ") + + if entrada == "": + pedir_entrada("¿Desea salir de la calculadora? (s/n) ") + if entrada == "s": + print("Bye bye...") + desea_salir = True + + elif entrada == "lista": + print(obtener_operaciones()) + + elif entrada == "ce": + print("Resultado reiniciado a 0.") + pausa() + resultado -= resultado + limpiar_pantalla() + + elif entrada.startswith("decimales"): + # Extraemos las posiciones decimales y las convertimos a un valor entero + decimales = str(entrada.split()[1]) + print(f"Decimales configurados a {decimales}.") + + elif entrada == "calculo": + limpiar_pantalla() + print(realizar_calculo(decimales, resultado)) + + else: + mostrar_error(6) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/daw1b_calculadora/juan_calculadora_alumnos.py b/daw1b_calculadora/juan_calculadora_alumnos.py new file mode 100644 index 0000000..2032d92 --- /dev/null +++ b/daw1b_calculadora/juan_calculadora_alumnos.py @@ -0,0 +1,479 @@ + # TODO: ATENCIÓN!!! +# 1. Importar los paquetes necesarios +# 2. Usar la función mostrar_error para imprimir los errores por consola. +# 3. Los comentarios TODO os ayudan a resolver cada apartado de esta prueba. +# 4. CADA función SOLO puede tener una instrucción return. +# 5. En test_calculadora_alumnos.py crear el test unitario para la función es_resultado_negativo y hacer que todos los test unitarios se cumplan. +import os + +resultado = "0.0" +decimales = 2 + +# Mensajes de error predefinidos +MENSAJES_ERROR = ( + "Problemas al intentar limpiar la pantalla {error}", + "Error al configurar los decimales. Formato: decimales .", + "Entrada no válida. Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo.", + "Error: Introduzca un operador antes de otro número.", + "Comando no reconocido. Escriba 'lista' para ver las operaciones disponibles.", + "Error: no es posible la división por 0! Introduzca otro valor diferente a 0...", + "Se produjo un error: {error}") + + +# Operadores soportados por la calculadora +OPERADORES = ['+', '-', '*', 'x', '/', ':', '**', 'exp'] +# TODO: Ayuda: incluye en esta constante los símbolos que reconocerá la aplicación para el cálculo de las operaciones: +# '+' para la suma. +# '-' para la resta. +# 'x' o '*' para la multiplicación. +# '/' o ':' para la división. +# '**' o 'exp' para la potencia. + + + +def limpiar_pantalla(): + """ + Limpia la consola según el sistema operativo. + """ + # TODO: El desarrollo de esta función está incompleto y con errores. + if os.name == 'nt': # Para Windows + os.system('cls') + else: # Para Linux/Mac + os.system('clear') + """ + try: + os.system(clear if os.name = posix else cls) + # Otra forma de expresar la misma instrucción sería la siguiente: + # if os.name = posix: + # os.system(clear) + # else: + # os.system(cls) + except Exception as e: + """ + + + +def pausa(): + import time + print("Antes de declarar la función time.sleep") + time.sleep(1) + print("Después de declarar la función time.sleep") + """ + Pausa la ejecución del programa hasta que se pulse ENTER... "\nPresione ENTER para continuar..." + """ + # TODO: Desarrollar esta función según su documentación. + + +def mostrar_error(indice_error: int, msj_error = None): + + """ + Muestra un mensaje de error en la consola. + + Args: + indice_error (int): Índice del mensaje de error en MENSAJES_ERROR. + msj_error (str, opcional): Texto adicional para personalizar el mensaje de error. + """ + # TODO: + # 1. Corrige el error que existe a la hora de acceder a los mensajes de error que están en la constante + # MENSAJES_ERROR. A los elementos de una tupla se accede igual que a los caracteres de una + # cadena de caracteres. + # 2. Completa el código de esta función para que controle específicamente las excepciones IndexError y + # muestre el mensaje: "\n*ERROR* Mensaje de error no definido.\n" + # 3. También se pide que se controle cualquier otra excepción que se pueda producir y muestre el mensaje: + # "\n*ERROR* Problemas al mostrar error!\n{e}\n" + # 4. En esta función los mensajes de error deben mostrarse con print. + if msj_error != None: + print(f"\n*ERROR* {MENSAJES_ERROR.format(error = msj_error)}\n") + else: + print(f"\n*ERROR* {MENSAJES_ERROR}\n") + + +def sumar(operador, numero): + + num1 = round(num1) + num2 = round(num2) + + es_resultado_negativo = (num1 < 0) != (num2 < 0) + + print(int("num1 + num2")) + + + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la suma de ambos. + + + +def restar(operador, numero): + + num1 = round(num1) + num2 = round(num2) + + es_resultado_negativo = (num1 < 0) != (num2 < 0) + + print(int("num1 - num2")) + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la resta de ambos. + + + +def es_resultado_negativo(num1: float, num2: float) -> bool: + """Determina si el resultado de una operación entre num1 y num2 debe ser negativo.""" + # TODO: Realizar el desarrollo completo de esta función teniendo en cuenta la documentación y completándola también. + # Debe pasar las pruebas unitarias. + # Se trata de una función que os puede venir bien para utilizarla tanto en la función multiplicar, como en dividir. + # Ya que va a determinar si la multiplicación o división entre dos números debería ser de signo negativo o no. + + + +def multiplicar(): + + """ + Realiza la multiplicación ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la multiplicación. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de multiplicación de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la multiplicación con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 * 3.33, deberá convertirse en 5 * 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 * -5 = 25 + # 6. OBLIGATORIO usar un bucle for. + # 7. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + + +def dividir(): + """ + Realiza la división ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Dividendo. + num2 (float): Divisor. + + Returns: + int: Resultado de la división. + + Raises: + ZeroDivisionError: Si el divisor es cero. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de división de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la división con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 / 3.33, deberá convertirse en 5 / 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 / -5 = 1 + # 6. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + +def potencia(): + # TODO: + # 1. Realizar el desarrollo completo de esta función y su documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. PREMISAS a tener en cuenta: + # - Cualquier número elevado a 0 da como resultado 1. + # - Para simplificar esta función, vamos a suponer que un número elevado a un + # exponente negativo siempre dará 0 (aunque en realidad no es así matemáticamente) + # 4. Utiliza la función de multiplicar para realizar los cálculos que te + # harán falta en esta función (RECUERDA que no puedes usar directamente los operadores + # de Python para la multiplicación y división). + # 5. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + + +def pedir_entrada(msj: str) -> str: + entrada = input(msj) + entrada = entrada.strip().lower() + """ + Pide al usuario una entrada, elimina espacios por delante y por detrás y la convierte a minúsculas. + + Args: + msj (str): Mensaje para solicitar la entrada. + + Returns: + str: Entrada del usuario. + """ + # TODO: El desarrollo de esta función está incompleto, debéis terminarla teniendo en cuenta la documentación + return input(msj) + + + + + +def calcular_operacion(num1: float, num2: float, operador: str) -> float: + """ + Realiza la operación especificada entre num1 y num2 dependiendo del valor del operador. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + float: Resultado de la operación. + + Raises: + ZeroDivisionError: Si el divisor es cero. + """ + # TODO: El desarrollo de esta función está incompleto... completadla teniendo en cuenta la documentación + # y que debe realizar las llamadas adecuadas a las funciones ya creadas para realizar los distintos + # cálculos... sumar, restar, multiplicar, dividir y potencia. + # IMPORTANTE: Si hacemos caso a la documentación de esta función, NO debéis capturar la excepción + # ZeroDivisionError aquí, sino que hay que dejadla que se propague a la función llamante, realizar_calculo(), + # dónde se os indica cómo realizar la gestión de estos errores. + + return resultado + + + +def obtener_operaciones() -> str: + """ + Devuelve una cadena con la lista de operaciones disponibles en la calculadora. + + Returns: + (str): cadena de caracteres con la información de las operaciones disponibles. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + """ + Operaciones disponibles: + ce => Reiniciar resultado a 0 + decimales => Establecer decimales en resultado + cadena vacía + => Pregunta si desea salir + calculo => Iniciar cálculo secuencial + + => Suma + - => Resta + x o * => Multiplicación + / o : => División + ** o exp => Potencia + cancelar => vovler sin actualizar resultado de la calculadora + cadena vacía + => volver actualizando resultado de la calculadora + """ + + +def realizar_calculo(): + resultado = 0.0 + operando = True + + print("Comienza tu secuencia de cálculos. Escribe 'cancelar' para cancelar en cualquier momento.") + + while True: + if operando: + + entrada = input(f"Introduce un número (o 'cancelar' para salir, 'resultado' para usar el último resultado): ").strip() + + if entrada.lower() == 'cancelar': + print("Cálculo cancelado.") + return None + + if entrada.lower() == 'resultado': + + num = resultado + else: + try: + num = float(entrada) + except ValueError: + print("Entrada no válida. Debes ingresar un número.") + continue + + if resultado == 0.0: + resultado = num + else: + operador = input("Introduce un operador (+, -, *, /): ").strip() + + if operador == "+": + resultado += num + elif operador == "-": + resultado -= num + elif operador == "*": + resultado *= num + elif operador == "/": + if num == 0: + print("Error: División por cero no permitida.") + continue + resultado /= num + else: + print("Operador no válido. Debes usar uno de los siguientes: +, -, *, /.") + continue + + + continuar = input(f"Resultado actual: {resultado}. ¿Quieres realizar otra operación? (s/n): ").strip().lower() + + if continuar != 's': + print(f"Resultado final: {resultado}") + return resultado + + + operando = True + + """ + Realiza una secuencia de cálculos solicitando números y operadores al usuario. + + Args: + decimales (int): Número de decimales para el resultado. + resultado_almacenado (float): Valor almacenado en la calculadora. + + Returns: + float: Resultado final del cálculo o None si se cancela. + + Note: + * Dentro de esta función el usuario puede realizar cálculos secuenciales, es decir, + comenzará introduciendo un número, después un operador, y otro número... a partir + de aquí sobre el resultado acumulado, introducirá operador y número para seguir + realizando cálculos (ver ejemplos en README.md de la tarea en el repositorio de GitHub). + * El usuario es guiado para introducir números y operadores secuencialmente + para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el + resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado + de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el + resultado almacenado de la calculadora. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + + operador = None + resultado = None + realizando_calculos = True + + print("\n## Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo ##\n") + + while realizando_calculos: + entrada = pedir_entrada(f"\t (Cálculo = resultado) >> ") + + if entrada == "cancelar": + + + elif entrada == "": + + + elif entrada in OPERADORES: + operador = " " + + else: + # TODO: este código funciona cuando solucionéis que reconozca las variables resultado_almacenado y decimales. + # Pero no gestiona los posibles tipos de Excepciones que se pueden producir: + # - ValueError que debe mostrar el error que está en la posición 2 de MENSAJES_ERROR. + # - ZeroDivisionError que debe mostrar el error que está en la posición 5 de MENSAJES_ERROR. + # - Exception que debe mostrar el error que está en la posición 6 de MENSAJES_ERROR. + if entrada == "resultado": + entrada = resultado_almacenado + + try: + numero = float(entrada) + + if operador is not None: + if resultado is None: + resultado = 0 + resultado = round(calcular_operacion(resultado, numero, operador), decimales) + operador = None + + elif resultado is None: + resultado = numero + + else: + mostrar_error(3) + except + + +def main(comando, obtener_operadores): + # Menu disponible + print("\nOperaciones disponibles:") + print(" ce => Reiniciar resultado a 0") + print(" decimales => Establecer decimales en resultado") + print(" lista => Ver lista de operaciones") + print(" calculo => Iniciar cálculo secuencial") + print(" + => Suma") + print(" - => Resta") + print(" x o * => Multiplicación") + print(" / o : => División") + print(" ** o exp => Potencia") + print(" cancelar => Volver sin actualizar resultado de la calculadora") + print(" => Volver actualizando resultado de la calculadora") + print(" limpiar => Limpiar la pantalla de la consola") + + """ + Función principal de la calculadora. Gestiona la entrada del usuario y coordina las operaciones. + + Note: + El flujo del programa es el siguiente: + + 1. Inicia la calculadora mostrando el resultado almacenado por defecto (0.00). + + 2. El usuario ingresa un comando, que puede ser: + - "lista" para ver todas las operaciones disponibles. + - "ce" para reiniciar el resultado almacenado a 0. + - "decimales " para establecer el número de decimales mostrados en el resultado. + - "calculo" para iniciar una secuencia de cálculo paso a paso. + - Una entrada vacía y pulsa la tecla para salir de la calculadora. + + 3. Según el comando ingresado: + - El programa realiza la operación o ejecuta la acción indicada. + - Al ingresar "calculo": + * El usuario es guiado para introducir números y operadores secuencialmente para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el resultado almacenado de la calculadora. + + 4. La calculadora sigue ejecutándose hasta que el usuario confirma la salida al ingresar una entrada vacía y pulsar . + + 5. Finalmente, se limpia la pantalla, el programa se despide con el mensaje "\n\nBye, bye...\n\n" y termina. + """ + # TODO: Corrige los errores y haz que el main funcione correctamente... + + decimales = 2 + resultado = 0.0 + + while not desea_salir: + + + pedir_entrada(f"Operación (RES => resultado) >> ") + + if entrada == "": + pedir_entrada("¿Desea salir de la calculadora? (s/n) ") + if desea_salir == 's': + print("\nBye Bye...") + return True + else: + return False + + elif entrada == "lista": + obtener_operaciones + + elif entrada == "ce": + + + elif entrada.startswith("decimales"): + try: + # Extraemos las posiciones decimales y las convertimos a un valor entero + decimales = str(entrada.split()[1]) + + except ValueError: + print(f"Decimales configurados a {decimales}.") + elif entrada == "limpiar_pantalla": + limpiar_pantalla() + elif entrada == "calculo": + realizar_calculo(decimales, resultado) + + else: + mostrar_error +def desea_salir(): + + + +if __name__ == "__main__": + resultado = "0.0" + decimales = 2 + main() \ No newline at end of file diff --git a/daw1b_calculadora/pablo_calculadora_alumnos.py b/daw1b_calculadora/pablo_calculadora_alumnos.py index 67f3cd4..3729cce 100644 --- a/daw1b_calculadora/pablo_calculadora_alumnos.py +++ b/daw1b_calculadora/pablo_calculadora_alumnos.py @@ -26,9 +26,12 @@ OPERADORES = ( '+', '-', - 'x' '*', - '/' ':', - '**' 'exp', + 'x', + '*', + '/', + ':', + '**', + 'exp', ) @@ -53,11 +56,15 @@ def limpiar_pantalla(): -def pausa(): +def pausa(tecla_enter = False): """ Pausa la ejecución del programa hasta que se pulse ENTER... "\nPresione ENTER para continuar..." """ # TODO: Desarrollar esta función según su documentación. + + if tecla_enter == True: + input("\nPresione ENTER para continuar...") + def mostrar_error(indice_error: int, msj_error = None): @@ -77,13 +84,15 @@ def mostrar_error(indice_error: int, msj_error = None): # 3. También se pide que se controle cualquier otra excepción que se pueda producir y muestre el mensaje: # "\n*ERROR* Problemas al mostrar error!\n{e}\n" # 4. En esta función los mensajes de error deben mostrarse con print. - MENSAJES_ERROR = indice_error + #MENSAJES_ERROR = indice_error + indice_error = MENSAJES_ERROR if msj_error != None: - print(f"\n*ERROR* {MENSAJES_ERROR.format(error = msj_error)}\n") + print(f"\n*ERROR* {MENSAJES_ERROR.format(error = str(msj_error))}\n") else: - print(f"\n*ERROR* {MENSAJES_ERROR}\n") + print(f"\n*ERROR* {indice_error}\n") + def sumar(num1: float, num2: float) -> float: @@ -137,7 +146,7 @@ def es_resultado_negativo(num1: float, num2: float) -> bool: -def multiplicar(): +def multiplicar(num1: float, num2: float): """ Realiza la multiplicación ENTERA de dos números usando solo sumas y restas. @@ -162,6 +171,12 @@ def multiplicar(): # 6. OBLIGATORIO usar un bucle for. # 7. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + num1 = int(num1) + num2 = int(num2) + + for num1 in range(num2): + print(num1) + def dividir(): @@ -192,6 +207,8 @@ def dividir(): # 6. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + def potencia(): # TODO: # 1. Realizar el desarrollo completo de esta función y su documentación. @@ -250,9 +267,12 @@ def calcular_operacion(num1: float, num2: float, operador: str) -> float: resultado = sumar(num1, num2) elif operador == "-": - resultado = sumar(num1, num2) + resultado = restar(num1, num2) + + elif operador == "*" or operador == "x": + resultado = multiplicar(num1, num2) - return resultado + return float(resultado) @@ -330,7 +350,7 @@ def realizar_calculo(decimales: int, resultado_almacenado: float) -> float: operador = None resultado = None realizando_calculos = True - resultado = resultado_almacenado + resultado_almacenado = resultado print("\n## Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo ##\n") @@ -341,7 +361,8 @@ def realizar_calculo(decimales: int, resultado_almacenado: float) -> float: entrada = resultado elif entrada == "": - realizando_calculos = True + pausa(tecla_enter = True) + realizando_calculos = False elif entrada in OPERADORES: operador = entrada @@ -395,8 +416,8 @@ def realizar_calculo(decimales: int, resultado_almacenado: float) -> float: else: mostrar_error(3) - except ValueError: - mostrar_error(2) + except: + mostrar_error(f"Debes introducir un número decimal!!!") def main(): """ @@ -450,15 +471,18 @@ def main(): obtener_operaciones() elif entrada == "ce": - pass + resultado_almacenado = 0 elif entrada.startswith("decimales"): # Extraemos las posiciones decimales y las convertimos a un valor entero - decimales = str(entrada.split(".")[:-1]) + decimales = str(entrada.split(".")[-1]) print(f"Decimales configurados a {decimales}.") elif entrada == "calculo": - resultado_almacenado = realizar_calculo(resultado, resultado_almacenado) + #resultado = realizar_calculo(resultado, resultado_almacenado) + resultado = realizar_calculo(decimales, resultado) + resultado = resultado_almacenado + else: diff --git a/daw1b_calculadora/rocio_calculadora_alumnos.py b/daw1b_calculadora/rocio_calculadora_alumnos.py new file mode 100644 index 0000000..b414f18 --- /dev/null +++ b/daw1b_calculadora/rocio_calculadora_alumnos.py @@ -0,0 +1,498 @@ +# TODO: ATENCIÓN!!! +# 1. Importar los paquetes necesarios +# 2. Usar la función mostrar_error para imprimir los errores por consola. +# 3. Los comentarios TODO os ayudan a resolver cada apartado de esta prueba. +# 4. CADA función SOLO puede tener una instrucción return. +# 5. En test_calculadora_alumnos.py crear el test unitario para la función es_resultado_negativo y hacer que todos los test unitarios se cumplan. + +import os + +# Mensajes de error predefinidos +MENSAJES_ERROR = ( + "Problemas al intentar limpiar la pantalla {error}", + "Error al configurar los decimales. Formato: decimales .", + "Entrada no válida. Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo.", + "Error: Introduzca un operador antes de otro número.", + "Comando no reconocido. Escriba 'lista' para ver las operaciones disponibles.", + "Error: no es posible la división por 0! Introduzca otro valor diferente a 0...", + "Se produjo un error: {error}" +) + +# Operadores soportados por la calculadora +OPERADORES = ('+', '-', 'x', '*', '/', ':', '**', 'exp') + +# TODO: Ayuda: incluye en esta constante los símbolos que reconocerá la aplicación para el cálculo de las operaciones: +# '+' para la suma. +# '-' para la resta. +# 'x' o '*' para la multiplicación. +# '/' o ':' para la división. +# '**' o 'exp' para la potencia. + + + + +def limpiar_pantalla(): + """ + Limpia la consola según el sistema operativo. + """ + # TODO: El desarrollo de esta función está incompleto y con errores. + try: + if os.name == 'posix': + os.system('clear') + + else: + os.system('cls') + + except Exception: + mostrar_error(0) + + +def pausa(): + """ + Pausa la ejecución del programa hasta que se pulse ENTER... "\nPresione ENTER para continuar..." + """ + # TODO: Desarrollar esta función según su documentación. + + input("\nPresione ENTER para continuar...") + + +def mostrar_error(indice_error = None, msj_error = None): + """ + Muestra un mensaje de error en la consola. En caso de que no se especifique + el error muestra el mensaje 'error no definido'. + + Args: + indice_error (int): Índice del mensaje de error en MENSAJES_ERROR. + msj_error (str, opcional): Texto adicional para personalizar el mensaje de error. + + Raises: + NameError: cuando el indice_error no está dentro del rango 0-6. + """ + # TODO: + # 1. Corrige el error que existe a la hora de acceder a los mensajes de error que están en la constante + # MENSAJES_ERROR. A los elementos de una tupla se accede igual que a los caracteres de una + # cadena de caracteres. + # 2. Completa el código de esta función para que controle específicamente las excepciones IndexError y + # muestre el mensaje: "\n*ERROR* Mensaje de error no definido.\n" + # 3. También se pide que se controle cualquier otra excepción que se pueda producir y muestre el mensaje: + # "\n*ERROR* Problemas al mostrar error!\n{e}\n" + # 4. En esta función los mensajes de error deben mostrarse con print. + + try: + if indice_error == None: + print("\n*ERROR* Mensaje de error no definido.\n") + + elif indice_error < 0 or indice_error > 6: + raise NameError("No se ha indicado el índice del error") + + else: + if msj_error != None: + print(f"\n*ERROR* {MENSAJES_ERROR[indice_error].format(error = msj_error)}\n") + + else: + print(f"\n*ERROR* {MENSAJES_ERROR[indice_error]}\n") + + except NameError as e: + print(f"\n*ERROR* Problemas al mostrar error!\n{e}.\n") + + + +def sumar(num1: float, num2: float) -> int: + """ + Esta función realiza la suma entre dos números. + + Args: + num1 (float): número introducido. + num2 (float): número introducido. + + Returns: + res (int): número producto de la suma. + """ + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la suma de ambos. + + res = num1 + num2 + + return res + +def restar(num1: float, num2: float) -> int: + """ + Esta función realiza la resta entre dos números. + + Args: + num1 (float): número introducido. + num2 (float): número introducido. + + Returns: + res (int): número producto de la resta. + """ + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la resta de ambos. + + res = num1 - num2 + + return res + + +def es_resultado_negativo(num1: float, num2: float) -> bool: + """ + Determina si el resultado de una operación entre num1 y num2 debe ser negativo. + + Args: + num1 (float): primer número. + num2 (float): segundo número. + + Returns: + negativo (bool): valor que nos dice si es True que el resultado debe ser negativo o False + si debe ser positivo. + """ + # TODO: Realizar el desarrollo completo de esta función teniendo en cuenta la documentación y completándola también. + # Debe pasar las pruebas unitarias. + # Se trata de una función que os puede venir bien para utilizarla tanto en la función multiplicar, como en dividir. + # Ya que va a determinar si la multiplicación o división entre dos números debería ser de signo negativo o no. + + if str(num1)[0] =='-': + if str(num2)[0] == '-': + negativo = False + else: + negativo = True + else: + if str(num2)[0] == '-': + negativo = True + else: + negativo = False + + return negativo + + +def multiplicar(num1: float, num2: float) -> int: + """ + Realiza la multiplicación ENTERA de dos números usando solo sumas y restas. + Llama a la función es_resultado_negativo() para comprobar si el resutlado de la + operación debe ser positivo (False) o negativo (True). + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + res (int): Resultado de la multiplicación. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de multiplicación de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la multiplicación con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 * 3.33, deberá convertirse en 5 * 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 * -5 = 25 + # 6. OBLIGATORIO usar un bucle for. + # 7. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + negativo = es_resultado_negativo(num1, num2) + num1 = abs(num1) + num2 = abs(num2) + res = 0 + + for i in range(0, round(num2)+1, 1): + res += round(num1) + + if negativo == True: + res *= -1 + + + return res + + + +def dividir(num1: float, num2: float) -> int: + """ + Realiza la división ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Dividendo. + num2 (float): Divisor. + + Returns: + int: Resultado de la división. + + Raises: + ZeroDivisionError: Si el divisor es cero. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de división de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la división con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 / 3.33, deberá convertirse en 5 / 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 / -5 = 1 + # 6. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + dividendo = round(abs(num1)) + divisor = round(abs(num2)) + negativo = es_resultado_negativo(num1, num2) + res = 0 + + try: + while dividendo >= divisor: + dividendo = dividendo - divisor + res += 1 + + #res += dividendo + + if negativo == True: + res *= -1 + + except ZeroDivisionError: + mostrar_error(5) + + return res + + +def potencia(): + # TODO: + # 1. Realizar el desarrollo completo de esta función y su documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. PREMISAS a tener en cuenta: + # - Cualquier número elevado a 0 da como resultado 1. + # - Para simplificar esta función, vamos a suponer que un número elevado a un + # exponente negativo siempre dará 0 (aunque en realidad no es así matemáticamente) + # 4. Utiliza la función de multiplicar para realizar los cálculos que te + # harán falta en esta función (RECUERDA que no puedes usar directamente los operadores + # de Python para la multiplicación y división). + # 5. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + pass + +def pedir_entrada(msj: str) -> str: + """ + Pide al usuario una entrada, elimina espacios por delante y por detrás y la convierte a minúsculas. + + Args: + msj (str): Mensaje para solicitar la entrada. + + Returns: + str: Entrada del usuario. + """ + # TODO: El desarrollo de esta función está incompleto, debéis terminarla teniendo en cuenta la documentación + + + entrada = input(msj) + + return entrada + + +def calcular_operacion(num1: float, num2: float, operador: str) -> float: + """ + Realiza la operación especificada entre num1 y num2 dependiendo del valor del operador. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + float: Resultado de la operación. + + Raises: + ZeroDivisionError: Si el divisor es cero. + """ + # TODO: El desarrollo de esta función está incompleto... completadla teniendo en cuenta la documentación + # y que debe realizar las llamadas adecuadas a las funciones ya creadas para realizar los distintos + # cálculos... sumar, restar, multiplicar, dividir y potencia. + # IMPORTANTE: Si hacemos caso a la documentación de esta función, NO debéis capturar la excepción + # ZeroDivisionError aquí, sino que hay que dejadla que se propague a la función llamante, realizar_calculo(), + # dónde se os indica cómo realizar la gestión de estos errores. + + if operador == '+': + resultado = sumar(num1, num2) + + elif operador == '-': + resultado = restar(num1, num2) + + elif operador == 'x' or operador == '*': + resultado = multiplicar(num1, num2) + + elif operador == '/' or operador == ':': + resultado = dividir(num1, num2) + + elif operador == '**' or operador == 'exp': + resultado = potencia(num1, num2) + + + return float(resultado) + + + +def obtener_operaciones() -> str: + """ + Devuelve una cadena con la lista de operaciones disponibles en la calculadora. + + Returns: + (str): cadena de caracteres con la información de las operaciones disponibles. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + + print(""" + Operaciones disponibles: + ce => Reiniciar resultado a 0 + decimales => Establecer decimales en resultado + cadena vacía + => Pregunta si desea salir + calculo => Iniciar cálculo secuencial + + => Suma + - => Resta + x o * => Multiplicación + / o : => División + ** o exp => Potencia + cancelar => vovler sin actualizar resultado de la calculadora + cadena vacía + => volver actualizando resultado de la calculadora + """) + + + +def realizar_calculo(decimales: int, resultado_almacenado: float) -> float: + """ + Realiza una secuencia de cálculos solicitando números y operadores al usuario. + + Args: + decimales (int): Número de decimales para el resultado. + resultado (float): Valor almacenado en la calculadora. + + Returns: + float: Resultado final del cálculo o None si se cancela. + + Note: + * Dentro de esta función el usuario puede realizar cálculos secuenciales, es decir, + comenzará introduciendo un número, después un operador, y otro número... a partir + de aquí sobre el resultado acumulado, introducirá operador y número para seguir + realizando cálculos (ver ejemplos en README.md de la tarea en el repositorio de GitHub). + * El usuario es guiado para introducir números y operadores secuencialmente + para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el + resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado + de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el + resultado almacenado de la calculadora. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + + operador = None + resultado = None + realizando_calculos = True + + print("\n## Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo ##\n") + + while realizando_calculos: + entrada = pedir_entrada(f"\t (Cálculo = resultado) >> ") + + if entrada == "cancelar": + realizando_calculos = False + + elif entrada == "": + resultado_almacenado = resultado + realizando_calculos = False + + elif entrada in OPERADORES: + operador = entrada + + else: + # TODO: este código funciona cuando solucionéis que reconozca las variables resultado_almacenado y decimales. + # Pero no gestiona los posibles tipos de Excepciones que se pueden producir: + # - ValueError que debe mostrar el error que está en la posición 2 de MENSAJES_ERROR. + # - ZeroDivisionError que debe mostrar el error que está en la posición 5 de MENSAJES_ERROR. + # - Exception que debe mostrar el error que está en la posición 6 de MENSAJES_ERROR. + if entrada == "resultado": + entrada = resultado_almacenado + + try: + numero = float(entrada) + + if operador is not None: + if resultado is None: + resultado = 0 + resultado = round(calcular_operacion(resultado, numero, operador), decimales) + operador = None + + elif resultado is None: + resultado = numero + + else: + mostrar_error(3) + except: + pass + + +def main(): + """ + Función principal de la calculadora. Gestiona la entrada del usuario y coordina las operaciones. + + Note: + El flujo del programa es el siguiente: + + 1. Inicia la calculadora mostrando el resultado almacenado por defecto (0.00). + + 2. El usuario ingresa un comando, que puede ser: + - "lista" para ver todas las operaciones disponibles. + - "ce" para reiniciar el resultado almacenado a 0. + - "decimales " para establecer el número de decimales mostrados en el resultado. + - "calculo" para iniciar una secuencia de cálculo paso a paso. + - Una entrada vacía y pulsa la tecla para salir de la calculadora. + + 3. Según el comando ingresado: + - El programa realiza la operación o ejecuta la acción indicada. + - Al ingresar "calculo": + * El usuario es guiado para introducir números y operadores secuencialmente para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el resultado almacenado de la calculadora. + + 4. La calculadora sigue ejecutándose hasta que el usuario confirma la salida al ingresar una entrada vacía y pulsar . + + 5. Finalmente, se limpia la pantalla, el programa se despide con el mensaje "\n\nBye, bye...\n\n" y termina. + """ + # TODO: Corrige los errores y haz que el main funcione correctamente... + + decimales = 2 + resultado_almacenado = 0.0 + desea_salir = False + limpiar_pantalla() + print ("#CALCULADORA#") + + while not desea_salir: + + entrada = pedir_entrada(f"Operación (RES => {resultado_almacenado}) >> ") + + if entrada == "": + salir = pedir_entrada("¿Desea salir de la calculadora? (s/n) ").upper() + if salir == 'S' or salir == 'SI' or salir == 'SÍ': + desea_salir = True + elif salir == 'N' or salir == 'NO': + desea_salir = False + else: + mostrar_error(6, "Debe ser una respuesta de sí o no") + + elif entrada == "lista": + obtener_operaciones() + + elif entrada == "ce": + resultado = 0.0 + + elif entrada.startswith("decimales"): + # Extraemos las posiciones decimales y las convertimos a un valor entero + decimales = str(entrada.split()[1]) + print(f"Decimales configurados a {decimales}.") + + elif entrada == "calculo": + resultado_almacenado = realizar_calculo(decimales, resultado_almacenado) + + else: + mostrar_error(2) + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/daw1b_calculadora/rocio_test_calculadora.py b/daw1b_calculadora/rocio_test_calculadora.py new file mode 100644 index 0000000..0d6f159 --- /dev/null +++ b/daw1b_calculadora/rocio_test_calculadora.py @@ -0,0 +1,73 @@ + +import pytest + +from src.calculadora_alumnos import es_resultado_negativo, multiplicar, dividir, potencia + + +# TODO: Crear el test unitario para la función es_resultado_negativo. Verifica lo siguiente: +# Casos donde el resultado debe ser negativo (2 casos) +# Casos donde el resultado debe ser positivo (2 casos) + + + +def test_multiplicar(): + # Multiplicación con números positivos + assert multiplicar(3.421, 3.922) == 12 + assert multiplicar(7.11, 2.1) == 14 + + # Multiplicación con un número negativo + assert multiplicar(-3.477, 4.1) == -12 + assert multiplicar(5, -2) == -10 + + # Multiplicación de dos números negativos + assert multiplicar(-5, -3) == 15 + + # Multiplicación con cero + assert multiplicar(0, 5) == 0 + assert multiplicar(3, 0) == 0 + +def test_dividir(): + # División con números positivos + assert dividir(9.33, 3.122) == 3 + assert dividir(14.757, 4.968) == 3 + + # División con un número negativo + assert dividir(-12, 3) == -4 + assert dividir(14.223, -2) == -7 + + # División de dos números negativos + assert dividir(-15.899, -4.499) == 4 + + # División con redondeo a entero + assert dividir(10, 3.101) == 3 # 10 // 3 = 3 (redondeo esperado) + + # División por cero + with pytest.raises(ZeroDivisionError): + dividir(5, 0) + +@pytest.mark.parametrize( + "base, exponente, expected", + [ + (2, 3, 8), # 2^3 = 8 + (5, 0, 1), # 5^0 = 1 + (-2, 3, -8), # -2^3 = -8 (base negativa con exponente impar) + (-2, 4, 16), # -2^4 = 16 (base negativa con exponente par) + (10, 1, 10), # 10^1 = 10 + (3, -2, 0), # 3^-2 = 0 (se devuelve 0 para exponentes negativos) + (0, 5, 0), # 0^5 = 0 + (0, 0, 1), # 0^0 = 1 (por convención en muchas calculadoras) + (5, 2, 25), # 5^2 = 25 + ] +) +def test_potencia(base, exponente, expected): + """ + Prueba para la función potencia. + """ + assert potencia(base, exponente) == expected + + +def test_es_resultado_negativo(): + assert es_resultado_negativo(-2, -3) == False + assert es_resultado_negativo(12, 3) == False + assert es_resultado_negativo(-4, 3) == True + assert es_resultado_negativo(4, -3) == True diff --git a/daw1b_calculadora/sergio_calculadora_alumnos.py b/daw1b_calculadora/sergio_calculadora_alumnos.py new file mode 100644 index 0000000..5f095e2 --- /dev/null +++ b/daw1b_calculadora/sergio_calculadora_alumnos.py @@ -0,0 +1,539 @@ +# TODO: ATENCIÓN!!! +# 1. Importar los paquetes necesarios +# 2. Usar la función mostrar_error para imprimir los errores por consola. +# 3. Los comentarios TODO os ayudan a resolver cada apartado de esta prueba. +# 4. CADA función SOLO puede tener una instrucción return. +# 5. En test_calculadora_alumnos.py crear el test unitario para la función es_resultado_negativo y hacer que todos los test unitarios se cumplan. + +import os +import time + +# Mensajes de error predefinidos +MENSAJES_ERROR = ( + "Problemas al intentar limpiar la pantalla {error}", + "Error al configurar los decimales. Formato: decimales .", + "Entrada no válida. Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo.", + "Error: Introduzca un operador antes de otro número.", + "Comando no reconocido. Escriba 'lista' para ver las operaciones disponibles.", + "Error: no es posible la división por 0! Introduzca otro valor diferente a 0...", + "Se produjo un error: {error}" +) + +# Operadores soportados por la calculadora +OPERADORES =( + '+', + '-', + 'x', + '*', + '/', + ':', + '**' +) +# TODO: Ayuda: incluye en esta constante los símbolos que reconocerá la aplicación para el cálculo de las operaciones: +# "'+' para la suma". +# "'-' para la resta". +# "'x' o '*' para la multiplicación". +# "'/' o ':' para la división". +# "'**' o 'exp' para la potencia". + +def crear_entero(numero: float): + """ + Realiza el paso de numeros flotates a enteros. + + Args: + num1 (float): numero el cual queremos cambiar el formato. + + + Returns: + int: Resultado del numero formateado. + """ + resultado = " " + cadena = str(numero) + + if cadena.startswith("-"): + cadena = cadena[1:] + if cadena.count(".") > 0: + posicion_punto = cadena.find(".") + + + parte_entera = cadena[:posicion_punto] + parte_entera = int(parte_entera) + parte_decimal = cadena[posicion_punto:] + parte_decimal = float(parte_decimal) + + if parte_decimal >= 0.5: + resultado = parte_entera + 1 + else: + resultado = parte_entera + else: + resultado = int(cadena) + + return resultado + +def limpiar_pantalla(): + """ + Limpia la consola según el sistema operativo. + """ + # TODO: El desarrollo de esta función está incompleto y con errores. + try: + os.system("clear" if os.name == "posix" else "cls") + # Otra forma de expresar la misma instrucción sería la siguiente: + # if os.name = posix: + # os.system(clear) + # else: + # os.system(cls) + except Exception as e: + mostrar_error(f"Problemas al intentar limpiar la pantalla {e}") + + + +def pausa(tiempo = 0, tecla_enter = False, limpiar = True): + """ + Pausa la ejecución del programa hasta que se pulse ENTER... "\nPresione ENTER para continuar..." + + Args: + tiempo (int, opcional): Número de segundos para la pausa. Si es mayor a 0, se pausa + por este tiempo y se ignora `tecla_enter`. + tecla_enter (bool, opcional): Si es True y `tiempo` es 0, espera a que el usuario presione + ENTER para continuar. + limpiar (bool, opcional): Si es True, limpia la pantalla después de la pausa. + """ + # TODO: Desarrollar esta función según su documentación. + + if tecla_enter: + input("\nPresione ENTER para continuar...") + elif tiempo > 0: + time.sleep(tiempo) + + if limpiar: + limpiar_pantalla() + + +def mostrar_error(indice_error: int, msj_error = None): + """ + Muestra un mensaje de error en la consola. + + Args: + indice_error (int): Índice del mensaje de error en MENSAJES_ERROR. + msj_error (str, opcional): Texto adicional para personalizar el mensaje de error. + """ + # TODO: + # 1. Corrige el error que existe a la hora de acceder a los mensajes de error que están en la constante + # MENSAJES_ERROR. A los elementos de una tupla se accede igual que a los caracteres de una + # cadena de caracteres. + # 2. Completa el código de esta función para que controle específicamente las excepciones IndexError y + # muestre el mensaje: "\n*ERROR* Mensaje de error no definido.\n" + # 3. También se pide que se controle cualquier otra excepción que se pueda producir y muestre el mensaje: + # "\n*ERROR* Problemas al mostrar error!\n{e}\n" + # 4. En esta función los mensajes de error deben mostrarse con print. + try: + if msj_error != None: + print(f"\n*ERROR* {MENSAJES_ERROR.format(error = msj_error)}\n") + else: + print(f"\n*ERROR* {MENSAJES_ERROR[indice_error]}\n") + + except IndexError as e: + print(f"\n*ERROR* Problemas al mostrar error!\n{e}\n") + + +def sumar(num1: float,num2: float): + """ + Realiza la suma de dos numero. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la suma. + """ + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la suma de ambos. + + return num1 + num2 + + +def restar(num1: float,num2: float): + """ + Realiza la resta de dos numero. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la resta. + """ + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la resta de ambos. + return num1 - num2 + + +def es_resultado_negativo(num1: float, num2: float) -> bool: + """Determina si el resultado de una operación entre num1 y num2 debe ser negativo.""" + # TODO: Realizar el desarrollo completo de esta función teniendo en cuenta la documentación y completándola también. + # Debe pasar las pruebas unitarias. + # Se trata de una función que os puede venir bien para utilizarla tanto en la función multiplicar, como en dividir. + # Ya que va a determinar si la multiplicación o división entre dos números debería ser de signo negativo o no. + + condicion_cuenta = "" + + num1_cadena,num2_cadena = str(num1),str(num2) + + if num1_cadena.startswith("-") and not num2_cadena.startswith("-"): + condicion_cuenta = True + + elif not num1_cadena.startswith("-") and num2_cadena.startswith("-"): + condicion_cuenta = True + + else: + condicion_cuenta = False + + return condicion_cuenta + + + + +def multiplicar(num1 : float,num2 : float): + + + """ + Realiza la multiplicación ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la multiplicación. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de multiplicación de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la multiplicación con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 * 3.33, deberá convertirse en 5 * 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 * -5 = 25 + # 6. OBLIGATORIO usar un bucle for. + # 7. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + + resultado = 0 + cal_num1 = crear_entero(num1) + cal_num2 = crear_entero(num2) + + for _ in range(1,cal_num2 + 1,1): + resultado += cal_num1 + + if es_resultado_negativo(num1,num2): + resultado = str(resultado) + resultado = "-" + resultado + resultado = int(resultado) + + return resultado + + + +def dividir(num1,num2): + """ + Realiza la división ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Dividendo. + num2 (float): Divisor. + + Returns: + int: Resultado de la división. + + Raises: + ZeroDivisionError: Si el divisor es cero. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de división de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la división con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 / 3.33, deberá convertirse en 5 / 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 / -5 = 1 + # 6. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + resultado = 0 + cal_num1 = crear_entero(num1) + cal_num2 = crear_entero(num2) + + if cal_num2 == 0: + raise ZeroDivisionError("*Error*\nNo se puede dividir por 0") + + while not cal_num2 > cal_num1: + + cal_num1 = cal_num1 - cal_num2 + resultado += 1 + + if es_resultado_negativo(num1,num2): + resultado = str(resultado) + resultado = "-" + resultado + resultado = int(resultado) + + + return resultado + +def potencia(num1,num2): + # TODO: + # 1. Realizar el desarrollo completo de esta función y su documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. PREMISAS a tener en cuenta: + # - Cualquier número elevado a 0 da como resultado 1. + # - Para simplificar esta función, vamos a suponer que un número elevado a un + # exponente negativo siempre dará 0 (aunque en realidad no es así matemáticamente) + # 4. Utiliza la función de multiplicar para realizar los cálculos que te + # harán falta en esta función (RECUERDA que no puedes usar directamente los operadores + # de Python para la multiplicación y división). + # 5. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + resultado = " " + #Si es negativo supondremos el resultado como 0 + if num2 < 0: + resultado = 0 + else: + resultado = multiplicar(num1,num2) + + return resultado + +def pedir_entrada(msj: str) -> str: + """ + Pide al usuario una entrada, elimina espacios por delante y por detrás y la convierte a minúsculas. + + Args: + msj (str): Mensaje para solicitar la entrada. + + Returns: + str: Entrada del usuario. + """ + # TODO: El desarrollo de esta función está incompleto, debéis terminarla teniendo en cuenta la documentación + return input(msj).lower().split() + + +def calcular_operacion(num1: float, num2: float, operador: str) -> float: + """ + Realiza la operación especificada entre num1 y num2 dependiendo del valor del operador. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + float: Resultado de la operación. + + Raises: + ZeroDivisionError: Si el divisor es cero. + """ + # TODO: El desarrollo de esta función está incompleto... completadla teniendo en cuenta la documentación + # y que debe realizar las llamadas adecuadas a las funciones ya creadas para realizar los distintos + # cálculos... sumar, restar, multiplicar, dividir y potencia. + # IMPORTANTE: Si hacemos caso a la documentación de esta función, NO debéis capturar la excepción + # ZeroDivisionError aquí, sino que hay que dejadla que se propague a la función llamante, realizar_calculo(), + # dónde se os indica cómo realizar la gestión de estos errores. + + resultado = "" + + if operador == '+': + resultado = sumar(num1,num2) + + if operador == '-': + resultado = sumar(num1,num2) + + if operador == 'x' or operador == '*': + resultado = multiplicar(num1,num2) + + if operador == 'x' or operador == '*': + resultado = dividir(num1,num2) + + if operador == '**' or operador == 'exp': + resultado = potencia(num1,num2) + + return resultado + + +def obtener_operaciones() -> str: + """ + Devuelve una cadena con la lista de operaciones disponibles en la calculadora. + + Returns: + (str): cadena de caracteres con la información de las operaciones disponibles. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + """ + Operaciones disponibles: + ce => Reiniciar resultado a 0 + decimales => Establecer decimales en resultado + cadena vacía + => Pregunta si desea salir + calculo => Iniciar cálculo secuencial + + => Suma + - => Resta + x o * => Multiplicación + / o : => División + ** o exp => Potencia + cancelar => vovler sin actualizar resultado de la calculadora + cadena vacía + => volver actualizando resultado de la calculadora + """ + cadena = "ce => Reiniciar resultado a 0\n" + +"decimales => Establecer decimales en resultado \n" + + "cadena vacía + => Pregunta si desea salir \n" + + "calculo => Iniciar cálculo secuencial \n" + + "\t+ => Suma \n" + + "\t- => Resta \n" + + "\tx o * => Multiplicación \n" + + "\t/ o : => División \n" + + "\t** o exp => Potencia \n" + + "\tcancelar => vovler sin actualizar resultado de la calculadora \n" + + "\tcadena vacía + => volver actualizando resultado de la calculadora \n" + + return cadena + + +def realizar_calculo(decimales: int,resultado_almacenado : float): + """ + Realiza una secuencia de cálculos solicitando números y operadores al usuario. + + Args: + decimales (int): Número de decimales para el resultado. + resultado_almacenado (float): Valor almacenado en la calculadora. + + Returns: + float: Resultado final del cálculo o None si se cancela. + + Note: + * Dentro de esta función el usuario puede realizar cálculos secuenciales, es decir, + comenzará introduciendo un número, después un operador, y otro número... a partir + de aquí sobre el resultado acumulado, introducirá operador y número para seguir + realizando cálculos (ver ejemplos en README.md de la tarea en el repositorio de GitHub). + * El usuario es guiado para introducir números y operadores secuencialmente + para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el + resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado + de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el + resultado almacenado de la calculadora. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + + operador = None + resultado = None + realizando_calculos = True + + print("\n## Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo ##\n") + + while realizando_calculos: + entrada = pedir_entrada(f"\t (Cálculo = resultado) >> ") + + if entrada == "cancelar": + realizando_calculos = False + + elif entrada == "": + realizando_calculos = False + + elif entrada in OPERADORES: + operador = OPERADORES[entrada] + + else: + # TODO: este código funciona cuando solucionéis que reconozca las variables resultado_almacenado y decimales. + # Pero no gestiona los posibles tipos de Excepciones que se pueden producir: + # - ValueError que debe mostrar el error que está en la posición 2 de MENSAJES_ERROR. + # - ZeroDivisionError que debe mostrar el error que está en la posición 5 de MENSAJES_ERROR. + # - Exception que debe mostrar el error que está en la posición 6 de MENSAJES_ERROR. + if entrada == "resultado": + entrada = resultado_almacenado + + try: + numero = float(entrada) + + if operador is not None: + if resultado is None: + resultado = 0 + resultado = round(calcular_operacion(resultado, numero, operador), decimales) + operador = None + + elif resultado is None: + resultado = numero + + else: + mostrar_error(3) + except ValueError as e: + print(e) + except IndexError as a: + print(a) + except ZeroDivisionError as mensaje: + print(mensaje) + + +def main(): + """ + Función principal de la calculadora. Gestiona la entrada del usuario y coordina las operaciones. + + Note: + El flujo del programa es el siguiente: + + 1. Inicia la calculadora mostrando el resultado almacenado por defecto (0.00). + + 2. El usuario ingresa un comando, que puede ser: + - "lista" para ver todas las operaciones disponibles. + - "ce" para reiniciar el resultado almacenado a 0. + - "decimales " para establecer el número de decimales mostrados en el resultado. + - "calculo" para iniciar una secuencia de cálculo paso a paso. + - Una entrada vacía y pulsa la tecla para salir de la calculadora. + + 3. Según el comando ingresado: + - El programa realiza la operación o ejecuta la acción indicada. + - Al ingresar "calculo": + * El usuario es guiado para introducir números y operadores secuencialmente para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el resultado almacenado de la calculadora. + + 4. La calculadora sigue ejecutándose hasta que el usuario confirma la salida al ingresar una entrada vacía y pulsar . + + 5. Finalmente, se limpia la pantalla, el programa se despide con el mensaje "\n\nBye, bye...\n\n" y termina. + """ + # TODO: Corrige los errores y haz que el main funcione correctamente... + + decimales = 2 + resultado = 0.00 + + desea_salir = False + + while not desea_salir: + + entrada = pedir_entrada(f"Operación (RES => {resultado}) >> ") + + if entrada == "": + entrada_salida = pedir_entrada("¿Desea salir de la calculadora? (s/n) ") + + if entrada_salida == 's': + desea_salir = True + + + elif entrada == "lista": + obtener_operaciones() + + elif entrada == "ce": + resultado = 0.0 + + + elif entrada.startswith("decimales"): + # Extraemos las posiciones decimales y las convertimos a un valor entero + decimales = str(entrada.split()[1]) + print(f"Decimales configurados a {decimales}.") + + elif entrada == "calculo": + realizar_calculo(decimales, resultado) + + else: + mostrar_error(1,None) + +if __name__ == "__main__": + main() diff --git a/daw1b_calculadora/test_adrian_calculadora.py b/daw1b_calculadora/test_adrian_calculadora.py new file mode 100644 index 0000000..cf09181 --- /dev/null +++ b/daw1b_calculadora/test_adrian_calculadora.py @@ -0,0 +1,68 @@ +import pytest + +from src.probar_cosas import es_resultado_negativo, multiplicar, dividir, potencia + + +# TODO: Crear el test unitario para la función es_resultado_negativo. Verifica lo siguiente: +# Casos donde el resultado debe ser negativo (2 casos) +# Casos donde el resultado debe ser positivo (2 casos) +def test_es_resultado_negativo(): + assert es_resultado_negativo(5,5) == False + assert es_resultado_negativo(-5, -5) == False + assert es_resultado_negativo(5, -5) == True + assert es_resultado_negativo(2, -2) == True + +def test_multiplicar(): + # Multiplicación con números positivos + assert multiplicar(3.421, 3.922) == 12 + assert multiplicar(7.11, 2.1) == 14 + + # Multiplicación con un número negativo + assert multiplicar(-3.477, 4.1) == -12 + assert multiplicar(5, -2) == -10 + + # Multiplicación de dos números negativos + assert multiplicar(-5, -3) == 15 + + # Multiplicación con cero + assert multiplicar(0, 5) == 0 + assert multiplicar(3, 0) == 0 + +def test_dividir(): + # División con números positivos + assert dividir(9.33, 3.122) == 3 + assert dividir(14.757, 4.968) == 3 + + # División con un número negativo + assert dividir(-12, 3) == -4 + assert dividir(14.223, -2) == -7 + + # División de dos números negativos + assert dividir(-15.899, -4.499) == 4 + + # División con redondeo a entero + assert dividir(10, 3.101) == 3 # 10 // 3 = 3 (redondeo esperado) + + # División por cero + with pytest.raises(ZeroDivisionError): + dividir(5, 0) + +@pytest.mark.parametrize( + "base, exponente, expected", + [ + (2, 3, 8), # 2^3 = 8 + (5, 0, 1), # 5^0 = 1 + (-2, 3, -8), # -2^3 = -8 (base negativa con exponente impar) + (-2, 4, 16), # -2^4 = 16 (base negativa con exponente par) + (10, 1, 10), # 10^1 = 10 + (3, -2, 0), # 3^-2 = 0 (se devuelve 0 para exponentes negativos) + (0, 5, 0), # 0^5 = 0 + (0, 0, 1), # 0^0 = 1 (por convención en muchas calculadoras) + (5, 2, 25), # 5^2 = 25 + ] +) +def test_potencia(base, exponente, expected): + """ + Prueba para la función potencia. + """ + assert potencia(base, exponente) == expected \ No newline at end of file diff --git a/daw1b_calculadora/test_beni_calculadora.py b/daw1b_calculadora/test_beni_calculadora.py new file mode 100644 index 0000000..74f245d --- /dev/null +++ b/daw1b_calculadora/test_beni_calculadora.py @@ -0,0 +1,74 @@ + +import pytest + +from src.calculadora_alumnos import es_resultado_negativo, multiplicar, dividir, potencia + + +# TODO: Crear el test unitario para la función es_resultado_negativo. Verifica lo siguiente: +# Casos donde el resultado debe ser negativo (2 casos) +# Casos donde el resultado debe ser positivo (2 casos) + +def test_es_resultado_negativo(): + #Resultado positivo + assert es_resultado_negativo(-4.03, 9) == True + assert es_resultado_negativo(2, -23.43) == True + + #Resultado negativo + assert es_resultado_negativo(-4.03, -9) == False + assert es_resultado_negativo(2, 23.43) == False + + +def test_multiplicar(): + # Multiplicación con números positivos + assert multiplicar(3.421, 3.922) == 12 + assert multiplicar(7.11, 2.1) == 14 + + # Multiplicación con un número negativo + assert multiplicar(-3.477, 4.1) == -12 + assert multiplicar(5, -2) == -10 + + # Multiplicación de dos números negativos + assert multiplicar(-5, -3) == 15 + + # Multiplicación con cero + assert multiplicar(0, 5) == 0 + assert multiplicar(3, 0) == 0 + +def test_dividir(): + # División con números positivos + assert dividir(9.33, 3.122) == 3 + assert dividir(14.757, 4.968) == 3 + + # División con un número negativo + assert dividir(-12, 3) == -4 + assert dividir(14.223, -2) == -7 + + # División de dos números negativos + assert dividir(-15.899, -4.499) == 4 + + # División con redondeo a entero + assert dividir(10, 3.101) == 3 # 10 // 3 = 3 (redondeo esperado) + + # División por cero + with pytest.raises(ZeroDivisionError): + dividir(5, 0) + +@pytest.mark.parametrize( + "base, exponente, expected", + [ + (2, 3, 8), # 2^3 = 8 + (5, 0, 1), # 5^0 = 1 + (-2, 3, -8), # -2^3 = -8 (base negativa con exponente impar) + (-2, 4, 16), # -2^4 = 16 (base negativa con exponente par) + (10, 1, 10), # 10^1 = 10 + (3, -2, 0), # 3^-2 = 0 (se devuelve 0 para exponentes negativos) + (0, 5, 0), # 0^5 = 0 + (0, 0, 1), # 0^0 = 1 (por convención en muchas calculadoras) + (5, 2, 25), # 5^2 = 25 + ] +) +def test_potencia(base, exponente, expected): + """ + Prueba para la función potencia. + """ + assert potencia(base, exponente) == expected diff --git a/daw1b_calculadora/test_daniel_calculadora.py b/daw1b_calculadora/test_daniel_calculadora.py new file mode 100644 index 0000000..aefa57b --- /dev/null +++ b/daw1b_calculadora/test_daniel_calculadora.py @@ -0,0 +1,74 @@ + +import pytest + +from src.calculadora_alumnos import es_resultado_negativo, multiplicar, dividir, potencia + + +# TODO: Crear el test unitario para la función es_resultado_negativo. Verifica lo siguiente: +# Casos donde el resultado debe ser negativo (2 casos) +# Casos donde el resultado debe ser positivo (2 casos) + + + +def test_multiplicar(): + # Multiplicación con números positivos + assert multiplicar(3.421, 3.922) == 12 + assert multiplicar(7.11, 2.1) == 14 + + # Multiplicación con un número negativo + assert multiplicar(-3.477, 4.1) == -12 + assert multiplicar(5, -2) == -10 + + # Multiplicación de dos números negativos + assert multiplicar(-5, -3) == 15 + + # Multiplicación con cero + assert multiplicar(0, 5) == 0 + assert multiplicar(3, 0) == 0 + +def test_dividir(): + # División con números positivos + assert dividir(9.33, 3.122) == 3 + assert dividir(14.757, 4.968) == 3 + + # División con un número negativo + assert dividir(-12, 3) == -4 + assert dividir(14.223, -2) == -7 + + # División de dos números negativos + assert dividir(-15.899, -4.499) == 4 + + # División con redondeo a entero + assert dividir(10, 3.101) == 3 # 10 // 3 = 3 (redondeo esperado) + + # División por cero + with pytest.raises(ZeroDivisionError): + dividir(5, 0) + +@pytest.mark.parametrize( + "base, exponente, expected", + [ + (2, 3, 8), # 2^3 = 8 + (5, 0, 1), # 5^0 = 1 + (-2, 3, -8), # -2^3 = -8 (base negativa con exponente impar) + (-2, 4, 16), # -2^4 = 16 (base negativa con exponente par) + (10, 1, 10), # 10^1 = 10 + (3, -2, 0), # 3^-2 = 0 (se devuelve 0 para exponentes negativos) + (0, 5, 0), # 0^5 = 0 + (0, 0, 1), # 0^0 = 1 (por convención en muchas calculadoras) + (5, 2, 25), # 5^2 = 25 + ] +) +def test_potencia(base, exponente, expected): + """ + Prueba para la función potencia. + """ + assert potencia(base, exponente) == expected + +def test_es_resultado_negativo(): + assert (es_resultado_negativo(4,3)) == False + assert (es_resultado_negativo(4,-3)) == True + assert (es_resultado_negativo(-4,3)) == True + assert (es_resultado_negativo(-4,-3)) == False + + diff --git a/daw1b_calculadora/test_david_calculadora.py b/daw1b_calculadora/test_david_calculadora.py new file mode 100644 index 0000000..7aba6f3 --- /dev/null +++ b/daw1b_calculadora/test_david_calculadora.py @@ -0,0 +1,74 @@ + +import pytest + +from src.calculadora_alumnos import es_resultado_negativo, multiplicar, dividir, potencia + + +# TODO: Crear el test unitario para la función es_resultado_negativo. Verifica lo siguiente: +# Casos donde el resultado debe ser negativo (2 casos) +# Casos donde el resultado debe ser positivo (2 casos) + +def test_es_resultado_negativo(): + # Casos donde el resultado es negativo. + assert es_resultado_negativo(-4, 4) == True + assert es_resultado_negativo(5, -3) == True + + # Casos donde el resultado es positivo. + assert es_resultado_negativo(5, 4) == False + assert es_resultado_negativo(3, 8) == False + + +def test_multiplicar(): + # Multiplicación con números positivos + assert multiplicar(3.421, 3.922) == 12 + assert multiplicar(7.11, 2.1) == 14 + + # Multiplicación con un número negativo + assert multiplicar(-3.477, 4.1) == -12 + assert multiplicar(5, -2) == -10 + + # Multiplicación de dos números negativos + assert multiplicar(-5, -3) == 15 + + # Multiplicación con cero + assert multiplicar(0, 5) == 0 + assert multiplicar(3, 0) == 0 + +def test_dividir(): + # División con números positivos + assert dividir(9.33, 3.122) == 3 + assert dividir(14.757, 4.968) == 3 + + # División con un número negativo + assert dividir(-12, 3) == -4 + assert dividir(14.223, -2) == -7 + + # División de dos números negativos + assert dividir(-15.899, -4.499) == 4 + + # División con redondeo a entero + assert dividir(10, 3.101) == 3 # 10 // 3 = 3 (redondeo esperado) + + # División por cero + with pytest.raises(ZeroDivisionError): + dividir(5, 0) + +@pytest.mark.parametrize( + "base, exponente, expected", + [ + (2, 3, 8), # 2^3 = 8 + (5, 0, 1), # 5^0 = 1 + (-2, 3, -8), # -2^3 = -8 (base negativa con exponente impar) + (-2, 4, 16), # -2^4 = 16 (base negativa con exponente par) + (10, 1, 10), # 10^1 = 10 + (3, -2, 0), # 3^-2 = 0 (se devuelve 0 para exponentes negativos) + (0, 5, 0), # 0^5 = 0 + (0, 0, 1), # 0^0 = 1 (por convención en muchas calculadoras) + (5, 2, 25), # 5^2 = 25 + ] +) +def test_potencia(base, exponente, expected): + """ + Prueba para la función potencia. + """ + assert potencia(base, exponente) == expected diff --git a/daw1b_calculadora/test_inda_calculadora.py b/daw1b_calculadora/test_inda_calculadora.py new file mode 100644 index 0000000..e4002d1 --- /dev/null +++ b/daw1b_calculadora/test_inda_calculadora.py @@ -0,0 +1,73 @@ + +import pytest +from src.calculadora_alumnos import es_resultado_negativo, multiplicar, dividir, potencia + + +# TODO: Crear el test unitario para la función es_resultado_negativo. Verifica lo siguiente: +# Casos donde el resultado debe ser negativo (2 casos) +# Casos donde el resultado debe ser positivo (2 casos) + +def test_es_resultado_negativo(): + # Resultados negativos + assert es_resultado_negativo(4, -3) == -12 + assert es_resultado_negativo(2, -3) == -6 + + # Resultados positivos + assert es_resultado_negativo(4, 3) == 12 + assert es_resultado_negativo(2, 3) == 6 + + +def test_multiplicar(): + # Multiplicación con números positivos + assert multiplicar(3.421, 3.922) == 12 + assert multiplicar(7.11, 2.1) == 14 + + # Multiplicación con un número negativo + assert multiplicar(-3.477, 4.1) == -12 + assert multiplicar(5, -2) == -10 + + # Multiplicación de dos números negativos + assert multiplicar(-5, -3) == 15 + + # Multiplicación con cero + assert multiplicar(0, 5) == 0 + assert multiplicar(3, 0) == 0 + +def test_dividir(): + # División con números positivos + assert dividir(9.33, 3.122) == 3 + assert dividir(14.757, 4.968) == 3 + + # División con un número negativo + assert dividir(-12, 3) == -4 + assert dividir(14.223, -2) == -7 + + # División de dos números negativos + assert dividir(-15.899, -4.499) == 4 + + # División con redondeo a entero + assert dividir(10, 3.101) == 3 # 10 // 3 = 3 (redondeo esperado) + + # División por cero + with pytest.raises(ZeroDivisionError): + dividir(5, 0) + +@pytest.mark.parametrize( + "base, exponente, expected", + [ + (2, 3, 8), # 2^3 = 8 + (5, 0, 1), # 5^0 = 1 + (-2, 3, -8), # -2^3 = -8 (base negativa con exponente impar) + (-2, 4, 16), # -2^4 = 16 (base negativa con exponente par) + (10, 1, 10), # 10^1 = 10 + (3, -2, 0), # 3^-2 = 0 (se devuelve 0 para exponentes negativos) + (0, 5, 0), # 0^5 = 0 + (0, 0, 1), # 0^0 = 1 (por convención en muchas calculadoras) + (5, 2, 25), # 5^2 = 25 + ] +) +def test_potencia(base, exponente, expected): + """ + Prueba para la función potencia. + """ + assert potencia(base, exponente) == expected diff --git a/daw1b_calculadora/test_jangel_calculadora.py b/daw1b_calculadora/test_jangel_calculadora.py new file mode 100644 index 0000000..de3111f --- /dev/null +++ b/daw1b_calculadora/test_jangel_calculadora.py @@ -0,0 +1,80 @@ + +import pytest + +from src.calculadora_alumnos import es_resultado_negativo, multiplicar, dividir, potencia + + +# TODO: Crear el test unitario para la función es_resultado_negativo. Verifica lo siguiente: +# Casos donde el resultado debe ser negativo (2 casos) +# Casos donde el resultado debe ser positivo (2 casos) +@pytest.mark.parametrize( + "num1, num2, expected", + [ + (2, -1, True), # num1= 2 y num2= -1 = True + (-5, 2, True), # num1= -5 y num2= 2 = True + (-2, -3, False), # num1= -2 y num2= -3 = False + (2, 4, False), # num1= 2 y num2= 4 = False + ] +) +def test_es_resultado_negativo(num1, num2, expected): + """ + Prueba la funcion es negativo. + """ + assert es_resultado_negativo (num1, num2) == expected + + + +def test_multiplicar(): + # Multiplicación con números positivos + assert multiplicar(3.421, 3.922) == 12 + assert multiplicar(7.11, 2.1) == 14 + + # Multiplicación con un número negativo + assert multiplicar(-3.477, 4.1) == -12 + assert multiplicar(5, -2) == -10 + + # Multiplicación de dos números negativos + assert multiplicar(-5, -3) == 15 + + # Multiplicación con cero + assert multiplicar(0, 5) == 0 + assert multiplicar(3, 0) == 0 + +def test_dividir(): + # División con números positivos + assert dividir(9.33, 3.122) == 3 + assert dividir(14.757, 4.968) == 3 + + # División con un número negativo + assert dividir(-12, 3) == -4 + assert dividir(14.223, -2) == -7 + + # División de dos números negativos + assert dividir(-15.899, -4.499) == 4 + + # División con redondeo a entero + assert dividir(10, 3.101) == 3 # 10 // 3 = 3 (redondeo esperado) + + # División por cero + with pytest.raises(ZeroDivisionError): + dividir(5, 0) + +@pytest.mark.parametrize( + "base, exponente, expected", + [ + (2, 3, 8), # 2^3 = 8 + (5, 0, 1), # 5^0 = 1 + (-2, 3, -8), # -2^3 = -8 (base negativa con exponente impar) + (-2, 4, 16), # -2^4 = 16 (base negativa con exponente par) + (10, 1, 10), # 10^1 = 10 + (3, -2, 0), # 3^-2 = 0 (se devuelve 0 para exponentes negativos) + (0, 5, 0), # 0^5 = 0 + (0, 0, 1), # 0^0 = 1 (por convención en muchas calculadoras) + (5, 2, 25), # 5^2 = 25 + ] +) +def test_potencia(base, exponente, expected): + """ + Prueba para la función potencia. + """ + assert potencia(base, exponente) == expected diff --git a/daw1b_calculadora/test_sergio_calculadora.py b/daw1b_calculadora/test_sergio_calculadora.py new file mode 100644 index 0000000..9703d9e --- /dev/null +++ b/daw1b_calculadora/test_sergio_calculadora.py @@ -0,0 +1,70 @@ + +import pytest + +from src.calculadora_alumnos import es_resultado_negativo, multiplicar, dividir, potencia + + +# TODO: Crear el test unitario para la función es_resultado_negativo. Verifica lo siguiente: +# Casos donde el resultado debe ser negativo (2 casos) +# Casos donde el resultado debe ser positivo (2 casos) + +def test_es_resultado_negativo(): + assert es_resultado_negativo(-12,2) == True + assert es_resultado_negativo(12,-2) == True + assert es_resultado_negativo(-12,-2) == False + assert es_resultado_negativo(12,2) == False + +def test_multiplicar(): + # Multiplicación con números positivos + assert multiplicar(3.421, 3.922) == 12 + assert multiplicar(7.11, 2.1) == 14 + + # Multiplicación con un número negativo + assert multiplicar(-3.477, 4.1) == -12 + assert multiplicar(5, -2) == -10 + + # Multiplicación de dos números negativos + assert multiplicar(-5, -3) == 15 + + # Multiplicación con cero + assert multiplicar(0, 5) == 0 + assert multiplicar(3, 0) == 0 + +def test_dividir(): + # División con números positivos + assert dividir(9.33, 3.122) == 3 + assert dividir(14.757, 4.968) == 3 + + # División con un número negativo + assert dividir(-12, 3) == -4 + assert dividir(14.223, -2) == -7 + + # División de dos números negativos + assert dividir(-15.899, -4.499) == 4 + + # División con redondeo a entero + assert dividir(10, 3.101) == 3 # 10 // 3 = 3 (redondeo esperado) + + # División por cero + with pytest.raises(ZeroDivisionError): + dividir(5, 0) + +@pytest.mark.parametrize( + "base, exponente, expected", + [ + (2, 3, 8), # 2^3 = 8 (base positiva con exponente par) + (5, 0, 1), # 5^0 = 1 (devuelve 1 por exponente 0) + (-2, 3, -8), # -2^3 = -8 (base negativa con exponente impar) + (-2, 4, 16), # -2^4 = 16 (base negativa con exponente par) + (10, 1, 10), # 10^1 = 10 (es la base en si) + (3, -2, 0), # 3^-2 = 0 (se devuelve 0 para exponentes negativos) + (0, 5, 0), # 0^5 = 0 (multiplicar 5 veces 0) + (0, 0, 1), # 0^0 = 1 (por convención en muchas calculadoras) + (5, 2, 25), # 5^2 = 25 (base positiva con exponente impar) + ] +) +def test_potencia(base, exponente, expected): + """ + Prueba para la función potencia. + """ + assert potencia(base, exponente) == expected diff --git a/daw1b_calculadora/test_victor_calculadora.py b/daw1b_calculadora/test_victor_calculadora.py new file mode 100644 index 0000000..83b9ee6 --- /dev/null +++ b/daw1b_calculadora/test_victor_calculadora.py @@ -0,0 +1,70 @@ + +import pytest + +from src.calculadora_alumnos import es_resultado_negativo, multiplicar, dividir, potencia + + +# TODO: Crear el test unitario para la función es_resultado_negativo. Verifica lo siguiente: +def test_es_resultado_negativo(): +# Casos donde el resultado debe ser negativo (2 casos) + assert es_resultado_negativo(3.421, 3.922) == False + assert es_resultado_negativo(7.11, 2.1) == False +# Casos donde el resultado debe ser positivo (2 casos) + assert es_resultado_negativo(3.421, -3.922) == True + assert es_resultado_negativo(-7.11, 2.1) == True + + +def test_multiplicar(): + # Multiplicación con números positivos + assert multiplicar(3.421, 3.922) == 12 + assert multiplicar(7.11, 2.1) == 14 + + # Multiplicación con un número negativo + assert multiplicar(-3.477, 4.1) == -12 + assert multiplicar(5, -2) == -10 + + # Multiplicación de dos números negativos + assert multiplicar(-5, -3) == 15 + + # Multiplicación con cero + assert multiplicar(0, 5) == 0 + assert multiplicar(3, 0) == 0 + +def test_dividir(): + # División con números positivos + assert dividir(9.33, 3.122) == 3 + assert dividir(14.757, 4.968) == 3 + + # División con un número negativo + assert dividir(-12, 3) == -4 + assert dividir(14.223, -2) == -7 + + # División de dos números negativos + assert dividir(-15.899, -4.499) == 4 + + # División con redondeo a entero + assert dividir(10, 3.101) == 3 # 10 // 3 = 3 (redondeo esperado) + + # División por cero + with pytest.raises(ZeroDivisionError): + dividir(5, 0) + +@pytest.mark.parametrize( + "base, exponente, expected", + [ + (2, 3, 8), # 2^3 = 8 + (5, 0, 1), # 5^0 = 1 + (-2, 3, -8), # -2^3 = -8 (base negativa con exponente impar) + (-2, 4, 16), # -2^4 = 16 (base negativa con exponente par) + (10, 1, 10), # 10^1 = 10 + (3, -2, 0), # 3^-2 = 0 (se devuelve 0 para exponentes negativos) + (0, 5, 0), # 0^5 = 0 + (0, 0, 1), # 0^0 = 1 (por convención en muchas calculadoras) + (5, 2, 25), # 5^2 = 25 + ] +) +def test_potencia(base, exponente, expected): + """ + Prueba para la función potencia. + """ + assert potencia(base, exponente) == expected diff --git a/daw1b_calculadora/victor_calculadora_alumnos.py b/daw1b_calculadora/victor_calculadora_alumnos.py new file mode 100644 index 0000000..7353d38 --- /dev/null +++ b/daw1b_calculadora/victor_calculadora_alumnos.py @@ -0,0 +1,473 @@ +# TODO: ATENCIÓN!!! +# 1. Importar los paquetes necesarios +# 2. Usar la función mostrar_error para imprimir los errores por consola. +# 3. Los comentarios TODO os ayudan a resolver cada apartado de esta prueba. +# 4. CADA función SOLO puede tener una instrucción return. +# 5. En test_calculadora_alumnos.py crear el test unitario para la función es_resultado_negativo y hacer que todos los test unitarios se cumplan. + + + +# Mensajes de error predefinidos +import os + + +MENSAJES_ERROR = ( + "Problemas al intentar limpiar la pantalla {error}", + "Error al configurar los decimales. Formato: decimales .", + "Entrada no válida. Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo.", + "Error: Introduzca un operador antes de otro número.", + "Comando no reconocido. Escriba 'lista' para ver las operaciones disponibles.", + "Error: no es posible la división por 0! Introduzca otro valor diferente a 0...", + "Se produjo un error: {error}" +) + +# Operadores soportados por la calculadora +OPERADORES = "+", "-", "x", "*", "/", ":", "**", "exp" +# TODO: Ayuda: incluye en esta constante los símbolos que reconocerá la aplicación para el cálculo de las operaciones: +# '+' para la suma. +# '-' para la resta. +# 'x' o '*' para la multiplicación. +# '/' o ':' para la división. +# '**' o 'exp' para la potencia. + + + +def limpiar_pantalla(): + """ + Limpia la consola según el sistema operativo. + """ + # TODO: El desarrollo de esta función está incompleto y con errores. + try: + os.system("clear" if os.name == "posix" else "cls") + # Otra forma de expresar la misma instrucción sería la siguiente: + # if os.name = posix: + # os.system(clear) + # else: + # os.system(cls) + except Exception as e: + mostrar_error(0,f"{e}") + + +def pausa(): + """ + Pausa la ejecución del programa hasta que se pulse ENTER... "\nPresione ENTER para continuar..." + """ + # TODO: Desarrollar esta función según su documentación. + input("\nPresione ENTER para continuar...") + + +def mostrar_error(indice_error: int, msj_error = None): + """ + Muestra un mensaje de error en la consola. + + Args: + indice_error (int): Índice del mensaje de error en MENSAJES_ERROR. + msj_error (str, opcional): Texto adicional para personalizar el mensaje de error. + """ + # TODO: + # 1. Corrige el error que existe a la hora de acceder a los mensajes de error que están en la constante + # MENSAJES_ERROR. A los elementos de una tupla se accede igual que a los caracteres de una + # cadena de caracteres. + # 2. Completa el código de esta función para que controle específicamente las excepciones IndexError y + # muestre el mensaje: "\n*ERROR* Mensaje de error no definido.\n" + # 3. También se pide que se controle cualquier otra excepción que se pueda producir y muestre el mensaje: + # "\n*ERROR* Problemas al mostrar error!\n{e}\n" + # 4. En esta función los mensajes de error deben mostrarse con print. + try: + if msj_error != None: + print(f"\n*ERROR* {MENSAJES_ERROR[indice_error].format(error = msj_error)}\n") + else: + print(f"\n*ERROR* {MENSAJES_ERROR[indice_error]}\n") + except IndexError: + print("\n*ERROR* Mensaje de error no definido.\n") + except Exception as e: + print(f"\n*ERROR* Problemas al mostrar error!\n{e}\n") + + +def sumar(num1: float, num2: float)-> float: + """ + Funcion que suma dos parametros de tipo decimal. + + Args: + num1 (float): Nº primero a sumar. + num2 (float): Nº segundo a sumar. + + Return: + float. + """ + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la suma de ambos. + suma = num1 + num2 + return suma + + +def restar(num1: float, num2: float)-> float: + """ + Funcion que resta dos parametros de tipo decimal. + + Args: + num1 (float): Nº primero al que restar. + num2 (float): Nº segundo que restará al primero. + Return: + float. + """ + # TODO: Realizar el desarrollo completo, incluida la documentación... recibe 2 números float y retorna la resta de ambos. + resta = num1 - num2 + return resta + + +def es_resultado_negativo(num1: float, num2: float) -> bool: + """Determina si el resultado de una operación entre num1 y num2 debe ser negativo. + + Args: + num1 (float): nº primero para determinar si es negativo o no + num2 (float): nº segundo para retornar si es negativo o no + + return: + bool: devuelve true en caso de que sea negativo y false si no lo es. + """ + # TODO: Realizar el desarrollo completo de esta función teniendo en cuenta la documentación y completándola también. + # Debe pasar las pruebas unitarias. + # Se trata de una función que os puede venir bien para utilizarla tanto en la función multiplicar, como en dividir. + # Ya que va a determinar si la multiplicación o división entre dos números debería ser de signo negativo o no. + if num1 < 0: + if num2 >= 0: + negativo = True + else: + negativo = False + else: + if num2 < 0: + negativo = True + else: + negativo = False + return negativo + + +def multiplicar(num1: float, num2: float)-> int: + """ + Realiza la multiplicación ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + + Returns: + int: Resultado de la multiplicación. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de multiplicación de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la multiplicación con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 * 3.33, deberá convertirse en 5 * 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 * -5 = 25 + # 6. OBLIGATORIO usar un bucle for. + # 7. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + num1 = round(num1) + num2 = round(num2) + resultado = 0 + negativo = False + + if num1 == 0 or num2 == 0: + resultado = 0 + + if num1 < 0: + num1 = -num1 + negativo = True + if num2 < 0: + num2 = -num2 + negativo = True + + for i in range(num2): + resultado = resultado + num1 + + if negativo: + resultado = -resultado + + return resultado + +def dividir(num1: float, num2: float)-> int: + """ + Realiza la división ENTERA de dos números usando solo sumas y restas. + + Args: + num1 (float): Dividendo. + num2 (float): Divisor. + + Returns: + int: Resultado de la división. + + Raises: + ZeroDivisionError: Si el divisor es cero. + + Note: + Debe redondear los números recibidos a enteros para trabajar. + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función teniendo en cuenta la documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. No podéis usar el operador de división de Python para realizar el desarrollo de la misma, + # es decir, que debéis realizar la división con SUMAS y/o RESTAS... + # 4. Aunque se reciben números de tipo float, debéis redondearlos como números enteros para + # simplificar esta función, es decir, la operación 4.98 / 3.33, deberá convertirse en 5 / 3. + # 5. Tened en cuenta que podéis recibir números negativos, es decir, la operación -5 / -5 = 1 + # 6. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + num1 = round(num1) + num2 = round(num2) + resultado = 0 + + if num2 == 0: + raise ZeroDivisionError("El divisor no puede ser 0.") + while resultado > num1: + resultado = num1 - num2 + + +def potencia(base: int, exponente: int)-> int: + """ + Funcion que eleva un nuemro a su exponente seleccionado. + + Args: + base (int): nº que va a ser elevado. + exponente (int): potencia a la que se elevará el nº base. + + Return: + int: devuelve un resultado entero. + + """ + # TODO: + # 1. Realizar el desarrollo completo de esta función y su documentación. + # 2. Esta función debe pasar las pruebas unitarias. + # 3. PREMISAS a tener en cuenta: + # - Cualquier número elevado a 0 da como resultado 1. + # - Para simplificar esta función, vamos a suponer que un número elevado a un + # exponente negativo siempre dará 0 (aunque en realidad no es así matemáticamente) + # 4. Utiliza la función de multiplicar para realizar los cálculos que te + # harán falta en esta función (RECUERDA que no puedes usar directamente los operadores + # de Python para la multiplicación y división). + # 5. Incluir algún comentario para mejorar la claridad y permitir que otros comprendan el propósito y funcionamiento del código. + return + + +def pedir_entrada(msj: str) -> str: + """ + Pide al usuario una entrada, elimina espacios por delante y por detrás y la convierte a minúsculas. + + Args: + msj (str): Mensaje para solicitar la entrada. + + Returns: + str: Entrada del usuario. + """ + # TODO: El desarrollo de esta función está incompleto, debéis terminarla teniendo en cuenta la documentación + return input(msj).strip().lower() + + +def calcular_operacion(num1: float, num2: float, operador: str) -> float: + """ + Realiza la operación especificada entre num1 y num2 dependiendo del valor del operador. + + Args: + num1 (float): Primer número. + num2 (float): Segundo número. + operador (str): Operador de la operación. + + Returns: + float: Resultado de la operación. + + Raises: + ZeroDivisionError: Si el divisor es cero. + """ + # TODO: El desarrollo de esta función está incompleto... completadla teniendo en cuenta la documentación + # y que debe realizar las llamadas adecuadas a las funciones ya creadas para realizar los distintos + # cálculos... sumar, restar, multiplicar, dividir y potencia. + # IMPORTANTE: Si hacemos caso a la documentación de esta función, NO debéis capturar la excepción + # ZeroDivisionError aquí, sino que hay que dejadla que se propague a la función llamante, realizar_calculo(), + # dónde se os indica cómo realizar la gestión de estos errores. + if operador in OPERADORES[0]: + resultado = sumar(num1, num2) + elif operador in OPERADORES[1]: + resultado = restar(num1, num2) + elif operador in OPERADORES[2] + OPERADORES[3]: + resultado = multiplicar(num1, num2) + elif operador in OPERADORES[4] + OPERADORES[5]: + resultado = dividir(num1, num2) + elif operador in OPERADORES[6] + OPERADORES[7]: + resultado = potencia() + + + return resultado + + + +def obtener_operaciones() -> str: + """ + Devuelve una cadena con la lista de operaciones disponibles en la calculadora. + + Returns: + (str): cadena de caracteres con la información de las operaciones disponibles. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + + + return """ + Operaciones disponibles: + ce => Reiniciar resultado a 0 + decimales => Establecer decimales en resultado + cadena vacía + => Pregunta si desea salir + calculo => Iniciar cálculo secuencial + + => Suma + - => Resta + x o * => Multiplicación + / o : => División + ** o exp => Potencia + cancelar => vovler sin actualizar resultado de la calculadora + cadena vacía + => volver actualizando resultado de la calculadora + """ + + +def realizar_calculo(decimales: int, resultado_almacenado: float)-> float: + """ + Realiza una secuencia de cálculos solicitando números y operadores al usuario. + + Args: + decimales (int): Número de decimales para el resultado. + resultado_almacenado (float): Valor almacenado en la calculadora. + + Returns: + float: Resultado final del cálculo o None si se cancela. + + Note: + * Dentro de esta función el usuario puede realizar cálculos secuenciales, es decir, + comenzará introduciendo un número, después un operador, y otro número... a partir + de aquí sobre el resultado acumulado, introducirá operador y número para seguir + realizando cálculos (ver ejemplos en README.md de la tarea en el repositorio de GitHub). + * El usuario es guiado para introducir números y operadores secuencialmente + para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el + resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado + de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el + resultado almacenado de la calculadora. + """ + # TODO: El desarrollo de esta función está incompleto... ver documentación para solucionarla correctamente. + + operador = None + resultado = None + realizando_calculos = True + + print("\n## Ingrese número, operador, 'resultado', 'cancelar' o para finalizar el cálculo ##\n") + + while realizando_calculos: + entrada = pedir_entrada(f"\t (Cálculo = {resultado}) >> ") + + if entrada == "cancelar": + realizando_calculos = False + + elif entrada == "": + realizando_calculos = False + + elif entrada in OPERADORES: + operador = entrada + + else: + # TODO: este código funciona cuando solucionéis que reconozca las variables resultado_almacenado y decimales. + # Pero no gestiona los posibles tipos de Excepciones que se pueden producir: + # - ValueError que debe mostrar el error que está en la posición 2 de MENSAJES_ERROR. + # - ZeroDivisionError que debe mostrar el error que está en la posición 5 de MENSAJES_ERROR. + # - Exception que debe mostrar el error que está en la posición 6 de MENSAJES_ERROR. + if entrada == "resultado": + entrada = resultado_almacenado + + try: + numero = float(entrada) + + if operador is not None: + if resultado is None: + resultado = 0 + resultado = round(calcular_operacion(resultado, numero, operador), decimales) + operador = None + + elif resultado is None: + resultado = numero + + else: + mostrar_error(3) + except ValueError: + mostrar_error(2) + except ZeroDivisionError: + mostrar_error(5) + except Exception: + mostrar_error(6) + + +def main(): + """ + Función principal de la calculadora. Gestiona la entrada del usuario y coordina las operaciones. + + Note: + El flujo del programa es el siguiente: + + 1. Inicia la calculadora mostrando el resultado almacenado por defecto (0.00). + + 2. El usuario ingresa un comando, que puede ser: + - "lista" para ver todas las operaciones disponibles. + - "ce" para reiniciar el resultado almacenado a 0. + - "decimales " para establecer el número de decimales mostrados en el resultado. + - "calculo" para iniciar una secuencia de cálculo paso a paso. + - Una entrada vacía y pulsa la tecla para salir de la calculadora. + + 3. Según el comando ingresado: + - El programa realiza la operación o ejecuta la acción indicada. + - Al ingresar "calculo": + * El usuario es guiado para introducir números y operadores secuencialmente para realizar operaciones básicas. + * El usuario puede utilizar "resultado" en la secuencia de cálculo para reutilizar el resultado almacenado en la calculadora. + * El cálculo finaliza al pulsar , volviendo y actualizando el resultado almacenado de la calculadora con el cálculo realizado. + * También podemos escribir "cancelar", volviendo sin realizar ningún cambio en el resultado almacenado de la calculadora. + + 4. La calculadora sigue ejecutándose hasta que el usuario confirma la salida al ingresar una entrada vacía y pulsar . + + 5. Finalmente, se limpia la pantalla, el programa se despide con el mensaje "\n\nBye, bye...\n\n" y termina. + """ + # TODO: Corrige los errores y haz que el main funcione correctamente... + + decimales = 2 + resultado = 0.0 + desea_salir = False + + while not desea_salir: + + entrada = pedir_entrada(f"Operación (RES => {resultado}) >> ") + + if entrada == "": + entrada = pedir_entrada("¿Desea salir de la calculadora? (s/n) ") + if entrada == "Si" or entrada == "s": + desea_salir = True + + elif entrada == "lista": + print(obtener_operaciones()) + + elif entrada == "ce": + resultado = 0 + + elif entrada.startswith("decimales"): + # Extraemos las posiciones decimales y las convertimos a un valor entero + decimales = str(entrada.split()[1]) + print(f"Decimales configurados a {decimales}.") + + elif entrada == "calculo": + realizar_calculo(decimales, resultado) + + else: + mostrar_error() + + limpiar_pantalla() + print("\n\nBye, bye...\n\n") + + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/tests/test_calculadora_alumnos.py b/tests/test_calculadora_alumnos.py index f48afb4..b4a7486 100644 --- a/tests/test_calculadora_alumnos.py +++ b/tests/test_calculadora_alumnos.py @@ -9,6 +9,15 @@ # Casos donde el resultado debe ser positivo (2 casos) +def test_es_resultado_negativo(): + # Casos donde el resultado debe ser negativo + assert es_resultado_negativo(-5, 3) is True + assert es_resultado_negativo(4, -7) is True + + # Casos donde el resultado debe ser positivo + assert es_resultado_negativo(5, 3) is False + assert es_resultado_negativo(-2, -8) is False + def test_multiplicar(): # Multiplicación con números positivos