Proszę o ocenę programu konwertującego liczby arabskie na rzymskie i na odwrót.
#include <iostream>
#include <string>
#include <sstream>
#include <cmath>
#include <limits>
using namespace std;
class Roman_int {
public:
Roman_int(int n) {
this->n = n;
}
Roman_int(const string& str) {
n = roman_to_int(str);
}
int as_int() const;
friend istream& operator>>(istream& ist, Roman_int& r);
friend ostream& operator<<(ostream& ost, const Roman_int& r);
private:
int roman_to_int(const string& roman);
string as_roman() const;
int n;
};
int Roman_int::roman_to_int(const string& roman) {
istringstream ist {roman};
int result = 0.0;
for (char ch; ist >> ch; ) {
switch (ch) {
case 'M':
result += 1000;
break;
case 'D':
result += 500;
break;
case 'C': {
char next;
ist >> next;
if (next == 'D' || next == 'M') {
result -= 100;
} else {
result += 100;
}
ist.putback(next);
break;
}
case 'L':
result += 50;
break;
case 'X': {
char next;
ist >> next;
if (next == 'L') {
result -= 10;
} else {
result += 10;
}
ist.putback(next);
break;
}
case 'V':
result += 5;
break;
case 'I': {
char next;
ist >> next;
if (next == 'V') {
result -= 1;
} else {
result += 1;
}
ist.putback(next);
break;
}
}
}
return result;
}
inline int nth_digit(int n, int k) {
return static_cast<int>(n/pow(10, k-1))%10;
}
string repeat(const string& s, int n) {
string res;
for (int i = 0; i < n; ++i) {
res += s;
}
return res;
}
string Roman_int::as_roman() const {
ostringstream ost;
int tho = nth_digit(n, 4);
if (tho >= 1 && tho <= 3) {
ost << repeat("M", tho);
}
int hun = nth_digit(n, 3);
if (hun >= 1 && hun <= 3) {
ost << repeat("C", hun);
} else if (hun == 4) {
ost << "CD";
} else if (hun >= 5 && hun <= 8) {
ost << "D" << repeat("C", hun - 5);
} else if (hun == 9) {
ost << "CM";
}
int dec = nth_digit(n, 2);
if (dec >= 1 && dec <= 3) {
ost << repeat("X", dec);
} else if (dec == 4) {
ost << "XL";
} else if (dec >= 5 && dec <= 8) {
ost << "L" << repeat("X", dec - 5);
} else if (dec == 9) {
ost << "XC";
}
int one = nth_digit(n, 1);
if (one >= 1 && one <= 3) {
ost << repeat("I", one);
} else if (one == 4) {
ost << "IV";
} else if (one >= 5 && one <= 8) {
ost << "V" << repeat("I", one - 5);
} else if (one == 9) {
ost << "IX";
}
return ost.str();
}
int Roman_int::as_int() const {
return n;
}
bool is_number(const string& str) {
for (char ch : str) {
if (!isdigit(ch)) return false;
}
return true;
}
istream& operator>>(istream& ist, Roman_int& r) {
string str;
ist >> str;
if (!ist) {
return ist;
}
if (is_number(str)) {
r.n = atoi(str.c_str());
} else {
r = Roman_int(str);
}
return ist;
}
ostream& operator<<(ostream& ost, const Roman_int& r) {
return ost << r.as_roman();
}
template <class T>
T read_input(const string& msg, const string& err) {
cout << msg << "\n> ";
T in;
while (!(cin >> in)) {
cout << err << '\n';
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << msg << "\n> ";
}
return in;
}
template <>
string read_input<string>(const string& msg, const string& err) {
cout << msg << "\n> ";
string in;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
while (!getline(cin, in)) {
cout << err << '\n';
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << msg << "\n> ";
}
return in;
}
int main() {
const string msg = "Co chcesz zrobić?\n"
"Dostępne opcje:\n"
"1) Zamiana liczby rzymskiej na normalną\n"
"2) Zamiana liczby zwykłej na rzymską\n"
"q) Koniec";
const string err = "Proszę podać liczbę.";
bool quit = false;
while (!quit) {
auto choice = read_input<char>(msg, err);
switch (choice) {
case '1': {
auto roman = read_input<string>("Podaj liczbę rzymską.", "Niepoprawna wartość!");
cout << "Rzymskie " << roman << " wynosi " << Roman_int(roman).as_int() << '\n';
break;
}
case '2': {
auto n = read_input<int>("Podaj liczbę zwykłą.", "Niepoprawna liczba!");
cout << n << " po rzymsku to " << Roman_int(n) << '\n';
break;
}
case 'q':
quit = true;
break;
default:
cout << "Niepoprawny wybór!\n";
break;
}
}
cout << "Do widzenia!\n";
return 0;
}