Преобразование римских цифр в Int - Получение неверного результата - Почему?

Вот мой код. Во-первых, я хочу сказать, что экспериментировал, поэтому, если вы видите здесь и там ненужные переменные, вот почему. Но основная часть моего кода находится в функции decimal моего класса romanType. Когда я ввожу определенные римские цифры, я не получаю те числа, которые мне нужны, и это может быть в моей логике где-то в моих операторах if / else.

Кстати, чтобы показать, как я двигаюсь по струне - я делаю это обратным ходом. Я иду от самого конца строки к самому началу строки, что, как мне кажется, проще с римскими цифрами. Между прочим, я также сделал тип перечисления, чтобы я мог сравнивать римские цифры, видя, какая из них меньше, какая больше и т. д. Затем я использовал карту, чтобы иметь возможность сравнивать значения перечисления со значением char.

Итак, проблема: например, когда я набираю CCC, я получаю 290 вместо 300. Если вы знаете, что не так в моей логике, я был бы очень признателен! Спасибо.

Кроме того, я новичок в программировании и был бы очень признателен за любые стилистические советы или все, что я могу узнать о классах и т. д., Которые я пропустил при написании этого кода? Пожалуйста, дайте мне знать, что лучше. Спасибо.

#include <iostream>
#include <string>
#include <map>

using namespace std;

class romanType {
string numeral;
int k;
 public:
romanType();
void rnumeral (string b) {numeral = b;}

int decimal(string num, char b, int temp) {
    num = "";


    enum RomanNumerals {I, V, X, L, C, D, M };

    map<char, RomanNumerals> m;

    m['I'] = I;
    m['V'] = V;
    m['X'] = X;
    m['L'] = L;
    m['C'] = C;
    m['D'] = D;
    m['M'] = M;


    RomanNumerals roman1;
    RomanNumerals roman2;


    cout << "Please type in your roman numeral:" ;

    cin >> num;

    for (int i =0; i <num.length()-1; i++){

    }

for(long i = num.length()-1; i>=0; i--)

{
b = num[i];
if (islower(b)) b=toupper(b);

roman1 = m[num[i]];
roman2 = m[num[i-1]];

switch(b){


            case 'I':
                    if (num[i] == num.length()-1){

                            temp += 1;
                            }
                        break;

            case 'V':

                if (roman1 > roman2){
                        temp += 4;
                        continue;
                        }

                else {
                    temp += 5;

                }

                break;


            case 'X':

                if (roman1 > roman2){
                    temp += 9;
                    continue;
                    }

            else {
                temp += 10;
                }

                break;

            case 'L' :

                if (roman1 > roman2){
                        temp += 40;
                        continue;
                    }

                else {
                    temp += 50;
                    }
                break;

            case 'C':

            if (roman1 > roman2){
                temp += 90;
                continue;
            }

            else {
                temp += 100;
            }

                break;

            case 'D' :
            if (roman1 > roman2){
                temp += 400;
                continue;
                }

            else {
                temp += 500;
                }
                break;

            case 'M':
            if (roman1 > roman2){
                temp += 900;
                continue;
                }

            else {
                temp += 1000;
                }
            break;

        }

    }


    return temp;
}
};

romanType::romanType () {
numeral = "";
}


int main() {
string k = "";
char b = ' ';
int temp = 0;

romanType type;
type.rnumeral(k);

int c = type.decimal(k, b, temp);

cout << c;


return 0;
}

Обновлено: _____________________________________________________________________________

Я нашел решение своей проблемы. Вот мой новый код:

#include <iostream>
#include <string>
#include <map>

using namespace std;

string acceptRN();



class romanType {

string numeral;
int temp2;
int l;
// VARIABLES
public:

romanType();
//DEFAULT CONSTRUCTOR


void getRnumeral (string b)
    {
        numeral = b;
    }
//SETTER

void decimal(string num, int temp, char b) {

    num = numeral;

    enum RomanNumerals {I, V, X, L, C, D, M };

    map<char, RomanNumerals> m;

    m['I'] = I;
    m['V'] = V;
    m['X'] = X;
    m['L'] = L;
    m['C'] = C;
    m['D'] = D;
    m['M'] = M;


    RomanNumerals roman1;
    RomanNumerals roman2;
    RomanNumerals roman3;





for(long i = num.length()-1; i>=0; i--)

{
b = num[i];
if (islower(b)) b=toupper(b);

roman1 = m[num[i]];
roman2 = m[num[i-1]];
roman3 = m[num[i+1]];

switch(b){


        case 'I':

        if ( roman3 > roman1 && i != num.length()-1){
            continue;
        }

        else {
                temp += 1;
                        break;
        }



            case 'V':

                if (roman1 > roman2 && i != 0){
                        temp += 4;
                        continue;
                        }

                else {
                    temp += 5;

                }

                break;


            case 'X':

        if ( roman3 > roman1 && i != num.length()-1)
            continue;

        if (roman1 > roman2 && i!= 0){
            temp += 9;
            continue;
                    }

            else {
                temp += 10;
                }

                break;

            case 'L' :

                if (roman1 > roman2 && i!= 0){

                        temp += 40;
                        continue;
                    }



                else {
                    temp += 50;
                    }
                break;

            case 'C':

            if ( roman3 > roman1 && i != num.length()-1)
                continue;

            if (roman2 == X && i!= 0){
                temp += 90;
                continue;
            }

            else {
                temp += 100;
            }

                break;

            case 'D' :
            if (roman2 == C && i!= 0){
                temp += 400;
                continue;
                }

            else {
                temp += 500;
                }
                break;

            case 'M':
            if (roman2 == C && i!= 0){
                temp += 900;
                continue;
                }

            else {
                temp += 1000;
                }
            break;


        }

    }
 temp2 = temp;
}

void showDecimal() {

cout << "Here is your roman numeral in decimal format:";
cout << temp2 << " \n \n \n";
}

};

romanType::romanType () {
numeral = "";



}


int main() {
string k = acceptRN();
int m = 0;
char l= ' ';

romanType type;
type.getRnumeral(k);
type.decimal(k, m, l);
type.showDecimal();


return 0;
}

string acceptRN(){
string num = "";
cout << "Please type in your roman numeral:" ;
cin >> num;

return num;

}

для начала вы можете избавиться от switch(b), если создадите таблицу, в которой будет буквальное десятичное значение ... int value[] = {1,5,10,...}, а затем просто используйте temp+=value[b];, значительно упростив ваш код. Тогда вы сможете легко отлаживать свой код, так как он сильно уменьшится.

Spektre 26.05.2018 09:51

Вы можете показать это в коде? Я не понимаю твоего ответа. @Spektre

Alexandra 26.05.2018 09:56

Смотрите мой ответ. Я попытался реализовать это в вашем коде, и это то, что я придумал, похоже, что он работает, но не тестировал его всесторонне ... в моем распоряжении не так много римских чисел ...

Spektre 26.05.2018 10:18

Одна вещь, которую я заметил, это то, что вы выполняете цикл до тех пор, пока i> = 0 и не используете номер [i-1]. Итак, вы читаете за пределами массива, который является UB.

super 26.05.2018 11:01
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
114
1

Ответы 1

Когда я закончил свой комментарий и немного подправил ваш код, я получил следующее:

//---------------------------------------------------------------------------
      int  roman_ix[256] = {-1};
const int  roman_val[] = { 1 , 5 ,10 ,50 ,100,500,1000,0};
const char roman_chr[] = {'I','V','X','L','C','D', 'M',0};
//---------------------------------------------------------------------------
int roman2int(char *s)
    {
    int i,x=0,v=0,v0;
    // init table (just once)
    if (roman_ix[0]<0)
        {
        for (i=0;i<256;i++) roman_ix[i]=0;
        for (i=0;roman_chr[i];i++) roman_ix[roman_chr[i]]=i;
        }
    // find end of string
    for (i=0;s[i];i++);
    // proccess string in reverse
    for (i--;i>=0;i--)
        {
        v0=v;                        // remember last digit
        v=roman_val[roman_ix[s[i]]]; // new digit
        if (!v) break;               // stop on non supported character
        if (v0>v) x-=v; else x+=v;   // add or sub
        }
    return x;
    }
//---------------------------------------------------------------------------

Я тестировал на них:

1776 1776 MDCCLXXVI
1954 1954 MCMLIV
1990 1990 MCMXC
2014 2014 MMXIV
 300  300 CCC

первое число преобразуется из строки, второе - это то, что должно быть, а последнее - римская строка.

Если таблица 256 записей слишком велика, вы можете сжать ее до диапазона A-Z, который значительно меньше, но требует еще одного вычитания в коде. Его также можно жестко запрограммировать, чтобы избавиться от инициализации:

//---------------------------------------------------------------------------
int roman2int(char *s)
    {
    // init
    int i,x=0,v=0,v0;       // A  B    C    D  E  F  G  H  I  J  K   L     M  N  O  P  Q  R  S  T  U  V  W   X  Y  Z
    const int val['Z'-'A'+1] = { 0, 0, 100, 500, 0, 0, 0, 0, 1, 0, 0, 50, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 10, 0, 0 };
    // find end of string
    for (i=0;s[i];i++);
    // process string in reverse
    for (i--;i>=0;i--)
        {
        if ((s[i]<'A')||(s[i]>'Z')) break; // stop on non supported character
        v0=v; v=val[s[i]-'A'];
        if (v0>v) x-=v; else x+=v;
        }
    return x;
    }
//---------------------------------------------------------------------------

Поскольку я избавился от ваших temp и roman1,roman2 и условий switch if/else, и код работал с первой компиляции ... Я предполагаю, что вы делаете с ними что-то подозрительное (потерялись в комбинациях if / else, пропавших без вести какой-то крайний случай).

Я считаю вашу первую версию действительно изящной!

Michael Beer 26.05.2018 11:14

Другие вопросы по теме