#include #include #include #include #include //----------------------------------------------------------------------------- // Classe para representar um nĂºmero racional p/q class Racional { // Representamos atraves de um numerador e denominador, normalizados de forma // que o seguinte seja sempre valido: // - denominador > 0 // - maximo divisor comum entre numerador e denominador vale 1 int _numerador; int _denominador; // Metodo privado para normalizar _numerador e _denominador, caso necessario. void _normaliza(); public: // Construtor de um racional. // Aceita dois inteiros quaisquer, mas denominador precisa ser diferente // de zero. Assume numerador 0 e denominador 1 se nao fornecido. // Este construtor funciona tambem para converter um int para um Racional. Racional(int numerador = 0, int denominador = 1) : _numerador(numerador), _denominador(denominador) { _normaliza(); } // Metodo para acessar numerador e denominador separadamente. std::tuple numerador_denominador() const { return {_numerador, _denominador}; } // Metodo para converter explicitamente o Racional para um double double para_double() const { return static_cast(_numerador) / _denominador; } // Operadores de atualizacao com operacoes aritmeticas. Racional &operator+=(Racional const &); Racional &operator-=(Racional const &); Racional &operator*=(Racional const &); Racional &operator/=(Racional const &); // Operadores aritmeticos friend Racional operator+(Racional const &, Racional const &); friend Racional operator-(Racional const &, Racional const &); friend Racional operator*(Racional const &, Racional const &); friend Racional operator/(Racional const &, Racional const &); friend Racional operator-(Racional const &a) { return {-a._numerador, a._denominador}; } // Operadores de comparacao. friend bool operator==(Racional const &a, Racional const &b) { return (a._numerador == b._numerador) && (a._denominador == b._denominador); } friend bool operator!=(Racional const &a, Racional const &b) { return !(a == b); } friend bool operator<(Racional const &a, Racional const &b); friend bool operator>(Racional const &a, Racional const &b) { return b < a; } friend bool operator>=(Racional const &a, Racional const &b) { return !(a < b); } friend bool operator<=(Racional const &a, Racional const &b) { return !(b < a); } // Operadores de auto-incremento e auto-decremento Racional &operator++() { // =+a // x/y + 1 => (x +y)/y _numerador += _denominador; _normaliza(); return *this; } Racional operator++(int) { // a++ Racional res{*this}; ++(*this); return res; } Racional &operator--() { // --a // x/y - 1 => (x - y)/y _numerador -= _denominador; _normaliza(); return *this; } Racional operator--(int) { // a-- Racional res{*this}; --(*this); return res; } // Operadores para escrita e leitura a partir de arquivos. friend std::ostream &operator<<(std::ostream &, Racional const &); friend std::istream &operator>>(std::istream &, Racional &); }; // Uma funcao main com alguns teste simples. int main(int, char const *[]) { Racional um_decimo{1, 10}; auto soma_tres = um_decimo + um_decimo + um_decimo; Racional tres_decimos{3, 10}; if (soma_tres == tres_decimos) { std::cout << "Funcionou!\n"; } else { std::cout << "Nao entende soma!\n"; } Racional outro{30, 100}; std::cout << "30/100 vale o mesmo que " << outro << " ou entao " << outro.para_double() << std::endl; if (outro != tres_decimos) { std::cout << "Nao entende fatores comuns!\n"; } auto dois_decimos = tres_decimos - um_decimo; if (dois_decimos != Racional{1, 5}) { std::cout << "Nao entende subtracao!\n"; } auto nove_centesimos = tres_decimos * outro; auto [nc_num, nc_den] = nove_centesimos.numerador_denominador(); std::cout << "Nove centesimos: " << nc_num << "/" << nc_den << std::endl; auto tres = tres_decimos / um_decimo; if (tres != Racional{3, 1}) { std::cout << "Nao entende divisao.\n"; } Racional mais_outro{-3, -10}; if (tres_decimos != mais_outro) { std::cout << "Nao entende negativos.\n"; } Racional rascunho; rascunho += Racional{1, 2}; if (rascunho != Racional{1, 2}) { std::cout << "Atualizacao com soma nao funciona.\n"; } rascunho -= Racional{1, 3}; if (rascunho != Racional{1, 6}) { std::cout << "Atualizacao com subtracao nao funciona.\n"; } rascunho *= 2; if (rascunho != Racional{1, 3}) { std::cout << "Atualizacao com produto nao funciona.\n"; } rascunho /= Racional{2, 5}; if (rascunho != Racional{5, 6}) { std::cout << "Atualizacao com divisao nao funciona.\n"; } if (!(um_decimo < tres_decimos)) { std::cout << "Nao sabe o que e menor.\n"; } if (!(tres_decimos > Racional{1, 5})) { std::cout << "Nao sabe o que e maior.\n"; } if (um_decimo >= tres_decimos) { std::cout << "Nao sabe o que e menor.\n"; } if (tres_decimos <= Racional{1, 5}) { std::cout << "Nao sabe o que e maior.\n"; } auto outro_rascunho1 = ++rascunho; auto outro_rascunho2 = rascunho++; std::cout << "Depois do pre-incremento " << outro_rascunho1 << std::endl; std::cout << "Depois do pos-incremento " << outro_rascunho2 << std::endl; std::cout << "Valor final " << rascunho << std::endl; std::cout << "Digite um racional no formato a/b para testar leitura: "; std::cin >> rascunho; std::cout << "Voce digitou " << rascunho << std::endl; return 0; } void Racional::_normaliza() { if (_denominador == 0) { // _denominador zero e um erro. std::cerr << "Denominador nulo nao permitido!\n"; exit(1); } // Agora _denominador != 0 if (_denominador < 0) { _numerador = -_numerador; _denominador = -_denominador; } // Agora _denominador > 0 auto fator_comum = std::gcd(_numerador, _denominador); _numerador /= fator_comum; _denominador /= fator_comum; // gcd(_numerador, _denominador) == 1 // Portanto esta estabelecido o invariante da classe. } Racional &Racional::operator+=(Racional const &b) { // Fazemos a operacao x/y + w/z => (x*z + w*y)/(y*z) _numerador = _numerador * b._denominador + b._numerador * _denominador; _denominador *= b._denominador; _normaliza(); return *this; } Racional &Racional::operator-=(Racional const &b) { // Fazemos a operacao x/y - w/z => (x*z - w*y)/(y*z) _numerador = _numerador * b._denominador - b._numerador * _denominador; _denominador *= b._denominador; _normaliza(); return *this; } Racional &Racional::operator*=(Racional const &b) { // Fazemos a operacao x/y * w/z => (x*w)/(y*z) _numerador *= b._numerador; _denominador *= b._denominador; _normaliza(); return *this; } Racional &Racional::operator/=(Racional const &b) { // Fazemos a operacao x/y * w/z => (x*w)/(y*z) _numerador *= b._denominador; _denominador *= b._numerador; _normaliza(); return *this; } // Os operadores aritmeticos sao implementados usando os correspondentes // operadores de autalizacao. Racional operator+(Racional const &a, Racional const &b) { Racional res{a}; res += b; return res; } Racional operator-(Racional const &a, Racional const &b) { Racional res{a}; res -= b; return res; } Racional operator*(Racional const &a, Racional const &b) { Racional res{a}; res *= b; return res; } Racional operator/(Racional const &a, Racional const &b) { Racional res{a}; res /= b; return res; } bool operator<(Racional const &a, Racional const &b) { // Basta verificar x/y < w/z => x*z < w*y return a._numerador * b._denominador < b._numerador * a._denominador; } std::ostream &operator<<(std::ostream &os, Racional const &r) { // Escrevemos no formato r._numerador/r._denominador os << r._numerador << "/" << r._denominador; return os; } std::istream &operator>>(std::istream &is, Racional &r) { // Lemos no format r._numerador/r._denominador // Variaveis auxiliares para ler numerador e denominador. int num, den; // Primeiro lemos um inteiro para o numerador is >> num; // Verificamos se deu tudo certo, se nao, retornamos. if (!is.good()) { return is; } // Agora lemos e ignoramos o caracter / char barra; is >> barra; // Verifica se conseguiu ler if (!is.good()) { return is; } // Se leu, verificamos se foi uma / if (barra != '/') { // Nao foi barra? Entao e um erro de formato. Ligamos failbit. is.setstate(std::ios_base::failbit); return is; } // Agora lemos um inteiro no denominador is >> den; // Se deu erro, retornamos if (!is.good()) { return is; } // Deu tudo certo, basta ajustar o valor de r: r = Racional{num, den}; return is; }