Conversor decimal para binário

Sep 28 2020

Este programa pode parecer preguiçoso, eu também tentei iterar por meio do vetor, mas o desempenho era ruim, então usei essa abordagem preguiçosa que tem mais desempenho

#ifndef BINARY_HH
#define BINARY_HH
/**************************************************************************
 * Name:  Binary.hh
 * Author: Samuel Oseh
 * Date: 27/09/2020
 * File Info: This file contains class method-function prototypes
 * Purpose: Binary Converter is a program that converts a decimal
 *          to its binary equivalents and also performs other calculations
 **************************************************************************/

#include <vector>
#include <string>

class Binary {
    public:
        Binary( const int &, const char & );
        ~Binary() {}
        Binary( const Binary & );
        void printBinary() const;
        void toBinary();
        char getType() const;
        int getDecimal() const;
        Binary &operator+=( const Binary &binaryToAdd );
        Binary &operator-=( const Binary &binaryToSub );
        Binary &operator*=( const Binary &binaryToMul );
        Binary &operator/=( const Binary &binaryToDiv );
        bool operator==( const Binary &binaryToCompare ) const;
        inline bool operator!=( const Binary &binaryToCompare ) const {
            return !( *this == binaryToCompare );
        }
        const Binary &operator=( const Binary &binaryToCopy );
    private:
        char type;
        int decimal;
        std::vector< int > binary{};
};

#endif

/**************************************************************************
 * Name:  Binary.cc
 * Author: Samuel Oseh
 * Date: 27/09/2020
 * File Info: This file contains class method-function definitions
 * Purpose: Binary Converter is a program that converts a decimal
 *          to its binary equivalents and also performs other calculations
 **************************************************************************/
#include <iostream>
#include <stdexcept>
#include "Binary.hh"

Binary::Binary( const int &d, const char &t ) {
    if ( tolower( t ) == 'd' )
        type = t;
    else
        throw std::invalid_argument( "type must be  'd' only." );
    if ( d < 0 )
        throw std::invalid_argument( "decimal value must be greater than 0." );
    decimal = d;
}

Binary::Binary( const Binary &binaryToCopy ) {
    decimal = binaryToCopy.decimal;
    type = binaryToCopy.type;
    for ( unsigned int counter = 0; counter < binaryToCopy.binary.size(); ++ counter ) {
        binary.push_back( binaryToCopy.binary[ counter ] );
    }
}

void Binary::toBinary() {
    if ( type == 'd' ) {
        int val = decimal;

        while ( val != 0 ) {
            binary.insert( binary.begin(), val % 2 );
            val /= 2;
        }
    }
    else {
        throw std::invalid_argument( "Invalid type conversion" );
    }
}

void Binary::printBinary() const {
    if ( binary.size() == 0 ) 
        throw std::invalid_argument( "Cannot print binary object without converting it" );
    for ( int number : binary ) {
        std::cout << number << "";
    }
}

char Binary::getType() const {
    return type;
}

int Binary::getDecimal() const {
    return decimal;
}

Binary &Binary::operator+=( const Binary &binaryToAdd ) { 
    if ( binary.size() == 0 ) 
        throw std::invalid_argument( "Cannot add binary object without converting it" );
    if ( binaryToAdd.binary.size() == 0 ) 
        throw std::invalid_argument( "Cannot add binary object without converting it" );

    int decimalSum = decimal + binaryToAdd.decimal;
    Binary *b = new Binary( decimalSum, 'd' );
    b->toBinary();
    *this = *b;
    delete b;
    return *this;
}

Binary &Binary::operator-=( const Binary &binaryToAdd ) { 
    if ( binary.size() == 0 ) 
        throw std::invalid_argument( "Cannot add binary object without converting it" );
    if ( binaryToAdd.binary.size() == 0 ) 
        throw std::invalid_argument( "Cannot add binary object without converting it" );

    int decimalSum = decimal - binaryToAdd.decimal;
    if ( decimalSum < 0 ) {
        throw std::invalid_argument( "Can not perform subtraction from a lesser binary" );
    }

    Binary *b = new Binary( decimalSum, 'd' );
    b->toBinary();
    *this = *b;
    delete b;
    return *this;
}

Binary &Binary::operator*=( const Binary &binaryToMul ) { 
    if ( binary.size() == 0 ) 
        throw std::invalid_argument( "Cannot add binary object without converting it" );
    if ( binaryToMul.binary.size() == 0 ) 
        throw std::invalid_argument( "Cannot add binary object without converting it" );

    int decimalSum = decimal * binaryToMul.decimal;
    Binary *b = new Binary( decimalSum, 'd' );
    b->toBinary();
    *this = *b;
    delete b;
    return *this;
}

Binary &Binary::operator/=( const Binary &binaryToDiv ) { 
    if ( binary.size() == 0 ) 
        throw std::invalid_argument( "Cannot add binary object without converting it" );
    if ( binaryToDiv.binary.size() == 0 ) 
        throw std::invalid_argument( "Cannot add binary object without converting it" );

    int decimalSum = decimal / binaryToDiv.decimal;
    Binary *b = new Binary( decimalSum, 'd' );
    b->toBinary();
    *this = *b;
    delete b;
    return *this;
}

bool Binary::operator==( const Binary &binaryToCompare ) const {
    if ( decimal == binaryToCompare.decimal )
        return true;
    return false;
}
const Binary &Binary::operator=( const Binary &binaryToCopy ) {
    decimal = binaryToCopy.decimal;
    type = binaryToCopy.type;
    binary.clear();
    for ( unsigned int counter = 0; counter < binaryToCopy.binary.size(); ++ counter ) {
        binary.push_back( binaryToCopy.binary[ counter ] );
    }
    return *this;
}

Respostas

7 MartinYork Sep 28 2020 at 14:57

Visão geral

Acho que a parte mais reveladora é esta:

        int decimal;

Provavelmente não é um número decimal. Na maioria dos computadores modernos, isso é armazenado como um número binário (embora em alguns computadores extremamente antigos eles usassem decimais, mas desistiram dos computadores decimais em favor do binário muito rapidamente).

O problema com o seu código é que um número é um número. Sua base só é importante quando você a visualiza, analisa ou armazena. Armazenar o número é uma abstração que a camada de hardware cuidou (o hardware sabe como armazenar / e realizar operações básicas em inteiros). Portanto, a única coisa para você é a camada de apresentação (impressão e análise).

Decimal 10:
Binary  1010
Hex     0xA

Tudo isso é simplesmente a representação visual do mesmo conceito. Já temos o conceito de um número inteiro fornecido pela linguagem que intrepresenta um valor.


Revisão de código

O tparâmetro de tipo é supérfluo aqui.

Binary :: Binary (const int & d, const char & t) {

O valor djá é um número. Você só precisa do tipo se estiver convertendo de uma representação visual (ou seja, uma string). Caso contrário, é sempre um número.


Não sei por que você não suporta valores negativos:

    if ( d < 0 )
        throw std::invalid_argument( "decimal value must be greater than 0."     

Não é tão difícil?


Isso pode ser simplificado:

    for ( unsigned int counter = 0; counter < binaryToCopy.binary.size(); ++ counter ) {
        binary.push_back( binaryToCopy.binary[ counter ] );
    }

    // Simpler to write:

    binary = binaryToCopy.binary;

Se você quiser armazenar localmente uma representação fácil de converter em texto, poderá usar std::bitset<32>.

std::bitset<32> binary;
void Binary::toBinary() {
    binary = decimal;  // converts it into a bitset.
                       // bitsset when put on a stream will show 1/0
                       // Note internally it is just an int.
}

Claro, é bom ter uma função de impressão.

void Binary::printBinary() const {

Mas em C ++ normalmente usamos operator<<para colocar dados em um fluxo de saída. Portanto, é bom escrever a função apropriada que faça isso. Não pode simplesmente chamar a printBinary()função. Mas você precisará modificar sua função de impressão para aceitar um fluxo (você pode padronizá-la std::outpara compatibilidade com versões anteriores.

    void Binary::printBinary(std::ostream& str = std::cout) const {
        binary.toBinary(); // You can convert see next section.
        out << binary;     // Assuming you used std::bitset.
    }
    friend std::ostream& operator<<(std::ostream& str, Binary const& b)
    {
        b.printBinary(str);
        return str;
    }

Você pode converter o número em um método const.

    if ( binary.size() == 0 ) 
        throw std::invalid_argument( "Cannot print binary object without converting it" );

O binaryobjeto está armazenando um estado temporário (ou seja, não representa o estado do objeto. Ele representa um valor fácil de imprimir do estado atual. Portanto, este é um lugar perfeito para marcar um membro como mutável.

    mutable std::bitset<32>    binary;

Agora você pode atualizar o estado em uma função const:


Uma vez que o valor foi convertido para um número, seu tipo é irelavant.

char Binary::getType() const {
    return type;
}

Você não está retornando um decimal. Você está devolvendo um número.

int Binary::getDecimal() const {
    return decimal;
}

Na verdade, é armazenado como binário, você sabe.


Uau, isso parece muito trabalho.

Binary &Binary::operator+=( const Binary &binaryToAdd ) { 
    if ( binary.size() == 0 ) 
        throw std::invalid_argument( "Cannot add binary object without converting it" );
    if ( binaryToAdd.binary.size() == 0 ) 
        throw std::invalid_argument( "Cannot add binary object without converting it" );

    int decimalSum = decimal + binaryToAdd.decimal;
    Binary *b = new Binary( decimalSum, 'd' );
    b->toBinary();
    *this = *b;
    delete b;
    return *this;
}

Primeiro, não vamos criar tipos dinâmicos:

    Binary *b = new Binary( decimalSum, 'd' );
    b->toBinary();
    *this = *b;
    delete b;

Isso pode ser simplificado para:

    Binary  b( decimalSum, 'd' );
    b.toBinary();
    *this = b;

Mas por que fazer tudo isso? Por que não simplificar mais uma etapa e remover o objeto intermediário?

    decimal += binaryToAdd.decimal;
    binary.clear();   // Not sure if you need this but probably.
    toBinary();

Não sabe por que eles já precisam ser convertidos?

    if ( binary.size() == 0 ) 
        throw std::invalid_argument( "Cannot add binary object without converting it" );
    if ( binaryToAdd.binary.size() == 0 ) 
        throw std::invalid_argument( "Cannot add binary object without converting it" );

Apenas se livre disso.


A mesma coisa se aplica aqui:

Binary &Binary::operator-=( const Binary &binaryToAdd ) { 
Binary &Binary::operator*=( const Binary &binaryToMul ) { 
Binary &Binary::operator/=( const Binary &binaryToDiv ) { 
   //  ^ Note in C++ (unlike C) the & and * go with the type (traditionally).

Você implementou a família de operadores + =. Isso torna a próxima etapa tão simples. Estou surpreso que você não implementou a família de operadores +.

Binary Binary::operator+(Binary const& rhs) const { 
    Binary newValue(*this);  // copy;
    return newValue += rhs;  // Add to the copy and return.
}

Isso pode ser simplificado:

    if ( decimal == binaryToCompare.decimal )
        return true;
    return false;

Para

    return decimal == binaryToCompare.decimal;

Se você se descobrir fazendo:

     if (test) {
         return true;
     }
     else {
         return false;
     }

     This is the same as

     return test; // as test must be a boolean value (or convertible to cone).