I've finally decided to design a class for this program, but some of the code still looks messy. I'm also a bit concerned about DRY, particularly in binaryToOctalHex()
. The program is looking better, but I'm still not liking what I'm doing in the aforementioned function. I don't mind refactoring that if necessary.
What should be done here?
Driver
#include <iostream>
#include "NumberSystemsConverter.h"
int main()
{
unsigned choice;
std::string str;
std::cout << "\n\n(1) Binary -> Decimal/Octal/Hex\n";
std::cout << "(2) Decimal -> Binary/Octal/Hex\n";
std::cout << "(3) Octal -> Binary/Decimal/Hex\n";
std::cout << "(4) Hex -> Binary/Decimal/Octal\n\n";
do
{
std::cout << "> Conversion #: ";
std::cin >> choice;
} while (choice < 1 || choice > 4);
std::cout << "\n> Value: ";
std::cin.ignore();
if (choice == 1)
{
std::string binary;
getline(std::cin, binary);
NumberSystemsConverter conversion(binary);
conversion.display();
}
else if (choice == 2)
{
d32 decimal;
std::cin >> decimal;
NumberSystemsConverter conversion(decimal);
conversion.display();
}
else if (choice == 3)
{
std::string octal;
getline(std::cin, octal);
NumberSystemsConverter conversion(8, octal);
conversion.display();
}
else if (choice == 4)
{
std::string hex;
getline(std::cin, hex);
NumberSystemsConverter conversion(16, hex);
conversion.display();
}
}
NumberSystemsConverter.h
#ifndef NUMBERSYSTEMSCONVERTER_H
#define NUMBERSYSTEMSCONVERTER_H
#include <cstdint>
#include <string>
typedef long double d32;
typedef std::uint32_t u32;
class NumberSystemsConverter
{
private:
d32 decimal;
std::string binary;
std::string octal;
std::string hex;
int findDecimalPoint(const std::string&) const;
void decimalToBinary();
void stringToDecimal(unsigned, const std::string&);
void binaryToOctal();
void binaryToHex();
public:
NumberSystemsConverter(const std::string&); // binary input
NumberSystemsConverter(d32); // decimal input
NumberSystemsConverter(unsigned, const std::string&); // octal/hex input
void display() const;
};
#endif
NumberSystemsConverter.cpp
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <sstream>
#include "NumberSystemsConverter.h"
NumberSystemsConverter::NumberSystemsConverter(const std::string &binary)
{
this->binary = binary;
stringToDecimal(2, binary);
binaryToOctal();
binaryToHex();
}
NumberSystemsConverter::NumberSystemsConverter(d32 decimal)
{
this->decimal = decimal;
decimalToBinary();
binaryToOctal();
binaryToHex();
}
NumberSystemsConverter::NumberSystemsConverter(unsigned base, const std::string &str)
{
if (base == 8)
{
octal = str;
stringToDecimal(base, octal);
decimalToBinary();
binaryToHex();
}
else if (base == 16)
{
hex = str;
stringToDecimal(base, hex);
decimalToBinary();
binaryToOctal();
}
}
int NumberSystemsConverter::findDecimalPoint(const std::string &str) const
{
int decimalPointIndex = str.find('.');
if (decimalPointIndex == std::string::npos)
decimalPointIndex = str.size(); // index identified as end if not found
return decimalPointIndex;
}
void NumberSystemsConverter::decimalToBinary()
{
binary = "";
u32 integerPart = static_cast<std::uint32_t>(decimal);
d32 decimalPart = decimal - integerPart;
do
{
binary += ((integerPart % 2 == 0) ? '0' : '1');
integerPart /= 2;
} while (integerPart > 0);
std::reverse(binary.begin(), binary.end());
if (decimalPart > 0.0)
{
binary += '.';
while (decimalPart != 1.0)
{
decimalPart *= 2.0;
binary += ((decimalPart < 1.0) ? '0' : '1');
if (decimalPart > 1.0) decimalPart -= 1.0;
}
}
}
void NumberSystemsConverter::stringToDecimal(unsigned base, const std::string &str)
{
int decimalPointIndex = findDecimalPoint(str);
d32 power = (d32)decimalPointIndex - 1;
decimal = 0.0;
// loops through entire string (not both sides of decimal point separately)
for (auto iter = str.cbegin(); iter != str.cend(); ++iter)
{
if (*iter != '.')
{
char strChar = toupper(*iter);
d32 charValue = strChar - ((isdigit(strChar)) ? '0' : '7');
decimal += charValue * (d32)std::pow(base, power);
}
else
power = 0.0;
power--;
}
}
void NumberSystemsConverter::binaryToOctal()
{
std::ostringstream octalSS;
std::string rightDecimal = "";
u32 rightValue = 0;
int decimalPointIndex = findDecimalPoint(binary);
const std::string::iterator iter = std::find(binary.begin(), binary.end(), '.');
std::string leftDecimal = binary.substr(0, decimalPointIndex);
u32 leftValue = std::stoul(leftDecimal, NULL, 2);
if (iter != binary.cend())
{
rightDecimal = binary.substr(decimalPointIndex+1, binary.size());
while (rightDecimal.size() % 3 != 0)
{
rightDecimal += '0';
}
rightValue = std::stoul(rightDecimal, NULL, 2);
}
octalSS << std::oct << leftValue << '.' << std::oct << rightValue;
octal = octalSS.str();
}
void NumberSystemsConverter::binaryToHex()
{
std::ostringstream hexSS;
std::string rightDecimal = "";
u32 rightValue = 0;
int decimalPointIndex = findDecimalPoint(binary);
const std::string::iterator iter = std::find(binary.begin(), binary.end(), '.');
std::string leftDecimal = binary.substr(0, decimalPointIndex);
u32 leftValue = std::stoul(leftDecimal, NULL, 2);
if (iter != binary.cend())
{
rightDecimal = binary.substr(decimalPointIndex+1, binary.size());
while (rightDecimal.size() % 4 != 0)
{
rightDecimal += '0';
}
rightValue = std::stoul(rightDecimal, NULL, 2);
}
hexSS << std::uppercase << std::hex << leftValue << '.' << std::hex << rightValue;
hex = hexSS.str();
}
void NumberSystemsConverter::display() const
{
std::cout << "\n * Binary : " << std::setprecision(10) << binary;
std::cout << "\n * Decimal: " << std::setprecision(10) << decimal;
std::cout << "\n * Octal : " << std::setprecision(10) << octal;
std::cout << "\n * Hex : 0x" << std::setprecision(10) << hex << "\n";
}