Prog. orientada a objetos

Práctica 1: Clase Fraction

Objetivos

Durante esta práctica, los alumnos serán capaces de:

Esta actividad promueve las siguientes habilidades, valores y actitudes: análisis y síntesis, capacidad de resolver problemas, creatividad, y uso eficiente de la informática y las telecomunicaciones.

IMPORTANTE

Para esta actividad de programación, el uso de herramientas asistidas por IA, como GitHub Copilot, ChatGPT, Gemini o plataformas similares, para generar código automáticamente está estrictamente prohibido. El uso de herramientas de IA de esta manera socava el proceso de aprendizaje y viola las políticas de integridad académica. El propósito de esta tarea es evaluar su comprensión y aplicación de los conceptos cubiertos en el curso. El incumplimiento de estas pautas puede resultar en sanciones académicas, que incluyen, entre otras, una calificación más baja.

Si tienes alguna pregunta sobre la tarea o necesitas una aclaración sobre algún concepto, no dudes en visitar a tu profesor durante las horas de asesoría. Confía únicamente en tu conocimiento, los materiales del curso y cualquier recurso autorizado proporcionado por el profesor.

Descripción de la actividad

Esta práctica debe ser elaborada en los equipos de dos personas ya constituidos.

Implementa una clase Fraction que incluya las funciones miembro (métodos) especificadas. Organiza el código en un directorio llamado fraction, en donde deberás colocar los archivos main.cpp, fraction.h y fraction.cpp.

Función miembro Descripción

Fraction(
    int numerator=0,
    int denominator=1,
)

Constructor: Inicializa un objeto Fraction que representa una fracción con un numerador entero (por defecto 0) y un denominador entero (por defecto 1). Internamente, la fracción se debe simplificar automáticamente a su forma más reducida.

Si el denominador es 0, se debe lanzar una excepción de tipo std::invalid_argument con el mensaje:

Denominator cannot be zero!

std::string to_string()
    const

Este método devuelve un std::string que representa el objeto Fraction en el formato "n/d", donde n es el numerador y d es el denominador. Pero, como caso especial, si el denominador es igual a 1, solo devuelve la cadena en el formato "n".

Si la fracción es negativa, el signo de menos (-) se debe incluir al inicio de la cadena.

Fraction operator + (
    const Fraction& other
) const

Suma (operador binario): regresa un nuevo objeto Fraction que resulta de sumar el objeto receptor más other.

Fórmula:

$$ \frac{a}{b} + \frac{c}{d} = \frac{(a \times d) + (b \times c)}{b \times d} $$

Fraction operator - () const

Negación (operador unario): regresa un nuevo objeto Fraction que resulta de cambiar el signo del objeto receptor.

Fórmula:

$$ -\left ( \frac{a}{b} \right ) = \frac{-a}{b} $$

Fraction operator - (
    const Fraction& other
) const

Resta (operador binario): regresa un nuevo objeto Fraction que resulta de restar el objeto receptor menos other.

Fórmula:

$$ \frac{a}{b} - \frac{c}{d} = \frac{a}{b} + -\left ( \frac{c}{d} \right ) $$

operator double() const;

Conversión a double (operador unario): regresa el resultado de convertir el objeto receptor a su valor de double correspondiente.

bool operator == (
    const Fraction& other
) const

Igualdad (operador binario): regresa true si el objeto receptor es igual a other, o false en caso contrario.

Fórmula\(^*\):

$$ \left ( \frac{a}{b} = \frac{c}{d} \right ) = [(a = c) \land (b = d)] $$

\(^*\) La formula supone que ambas fracciones están reducidas a su forma más simple.

bool operator != (
    const Fraction& other
) const

Desigualdad (operador binario): regresa true si el objeto receptor es diferente de other, o false en caso contrario.

Fórmula:

$$ \left ( \frac{a}{b} \ne \frac{c}{d} \right ) = \neg \left ( \frac{a}{b} = \frac{c}{d} \right ) $$

Fraction operator * (
    const Fraction& other
) const

Multiplicación (operador binario): regresa un nuevo objeto Fraction que resulta de multiplicar el objeto receptor por other.

Fórmula:

$$ \frac{a}{b} \times \frac{c}{d} = \frac{a \times c}{b \times d} $$

Fraction operator ~ () const

Recíproco (operador unario): regresa un nuevo objeto Fraction que resulta de obtener el recíproco del objeto receptor.

El recíproco de una fracción es un número que, al multiplicarse por el original, da como resultado uno, obteniéndose al intercambiar el numerador y el denominador del número original.

Fórmula:

$$ \left ( \frac{a}{b} \right )^{-1} = \frac{b}{a} $$

Fraction operator / (
    const Fraction& other
) const

División (operador binario): regresa un nuevo objeto Fraction que resulta de dividir el objeto receptor entre other.

Fórmula:

$$ \frac{a}{b} \div \frac{c}{d} = \frac{a}{b} \times \left ( \frac{c}{d} \right )^{-1} = \frac{a \times d}{b \times c} $$

bool operator < (
    const Fraction& other
) const

Menor que (operador binario): regresa true si el objeto receptor es menor que other, o false en caso contrario.

Fórmula:

$$ \left ( \frac{a}{b} < \frac{c}{d} \right ) = [(a \times d) < (b \times c)] $$

bool operator <= (
    const Fraction& other
) const

Menor o igual (operador binario): regresa true si el objeto receptor es menor o igual a other, o false en caso contrario.

Fórmula:

$$ \left ( \frac{a}{b} \le \frac{c}{d} \right ) = [(a \times d) \le (b \times c)] $$

bool operator > (
    const Fraction& other
) const

Mayor que (operador binario): regresa true si el objeto receptor es mayor que other, o false en caso contrario.

Fórmula:

$$ \left ( \frac{a}{b} > \frac{c}{d} \right ) = [(a \times d) > (b \times c)] $$

bool operator >= (
    const Fraction& other
) const

Mayor o igual (operador binario): regresa true si el objeto receptor es mayor o igual a other, o false en caso contrario.

Fórmula:

$$ \left ( \frac{a}{b} \ge \frac{c}{d} \right ) = [(a \times d) \ge (b \times c)] $$

También, debes incluir la sobrecarga del operador de inserción de flujo, operator<<. Esta función permitirá imprimir objetos Fraction de forma conveniente en flujos de salida como std::cout. Para ello, en el archivo fraction.h incluye la siguiente declaración fuera de la clase Fraction:

std::ostream& operator<<(std::ostream& os, const Fraction& r);

En el archivo fraction.cpp coloca la implementación de dicha función:

std::ostream& operator<<(std::ostream& os, const Fraction& r)
{
    return os << r.to_string();
}

Esta sobrecarga simplemente utiliza el método to_string() de la clase Fraction para obtener la representación en cadena del objeto y la escribe en el flujo de salida, asegurando una visualización consistente y amigable de las fracciones.

Prueba tu código utilizando el siguiente archivo main.cpp:

// Archivo: main.cpp

// Para compilar y correr:
//               
//     g++ *.cpp -o main && ./main

#include <iostream>
#include <iomanip>
#include <stdexcept>
#include "fraction.h"

int main()
{
    Fraction a(1, 2);
    Fraction b(6, 4);
    Fraction c(4, 8);
    Fraction d;
    Fraction e(-3);

    // Para imprimir los booleanos como true o false
    // en lugar de 1 o 0.
    std::cout << std::boolalpha;

    std::cout << "a: " << a << "\n";
    std::cout << "b: " << b << "\n";
    std::cout << "c: " << c << "\n";
    std::cout << "d: " << d << "\n";
    std::cout << "e: " << e << "\n";
    std::cout << "a + b: " << a + b << "\n";
    std::cout << "c + d: " << c + d << "\n";
    std::cout << "a == c: " << (a == c) << "\n";
    std::cout << "a == b: " << (a == b) << "\n";
    std::cout << "a != b: " << (a != b) << "\n";
    std::cout << "a != c: " << (a != c) << "\n";
    std::cout << "-a: " << -a << "\n";
    std::cout << "-e: " << -e << "\n";
    std::cout << "a - b: " << a - b << "\n";
    std::cout << "c - e: " << c - e << "\n";
    std::cout << "static_cast<double>(a): "
        << static_cast<double>(a) << "\n";
    std::cout << "static_cast<double>(b): "
        << static_cast<double>(b) << "\n";
    std::cout << "a * b: " << a * b << "\n";
    std::cout << "c * e: " << c * e << "\n";
    std::cout << "~b: " << ~b << "\n";
    std::cout << "~e: " << ~e << "\n";
    std::cout << "b * ~b: " << b * ~b << "\n";
    std::cout << "e * ~e: " << e * ~e << "\n";
    std::cout << "a / b: " << a / b << "\n";
    std::cout << "c / e: " << c / e << "\n";
    try {
        Fraction t = a / d;
        std::cout << "a / d: " << t << "\n";
    } catch (const std::invalid_argument& e) {
        std::cout << "a / d: " << e.what() << "\n";
    }
    std::cout << "a < b: " << (a < b) << "\n";
    std::cout << "a < c: " << (a < c) << "\n";
    std::cout << "a <= c: " << (a <= c) << "\n";
    std::cout << "a <= d: " << (a <= d) << "\n";
    std::cout << "b > c: " << (b > c) << "\n";
    std::cout << "a > c: " << (a > c) << "\n";
    std::cout << "a >= c: " << (a >= c) << "\n";
    std::cout << "e >= d: " << (e >= d) << "\n";
    return 0;
}

Asegúrate que la salida sea idéntica a lo siguiente:

a: 1/2
b: 3/2
c: 1/2
d: 0
e: -3
a + b: 2
c + d: 1/2
a == c: true
a == b: false
a != b: true
a != c: false
-a: -1/2
-e: 3
a - b: -1
c - e: 7/2
static_cast<double>(a): 0.5
static_cast<double>(b): 1.5
a * b: 3/4
c * e: -3/2
~b: 2/3
~e: -1/3
b * ~b: 1
e * ~e: 1
a / b: 1/3
c / e: -1/6
a / d: Denominator cannot be zero!
a < b: true
a < c: false
a <= c: true
a <= d: false
b > c: true
a > c: false
a >= c: true
e >= d: false

Consideraciones adicionales

¿Qué se debe entregar?

Crea un archivo comprimido TAR GZ o ZIP con el contenido completo del directorio fraction. El archivo resultante se debe llamar fraction.tar.gz o fraction.zip.

Instrucciones para subir archivo

Para entregar el archivo fraction.tar.gz/fraction.zip, ingresa los siguientes datos:

Solicitar NIP

Solo es necesario que lo entregue un miembro del equipo.

La fecha límite es el lunes 1 de junio.