Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Калькулятор с одним полем TEdit. Прошу проверить реализацию. 
V
    Опции темы
Dilettante
Дата 15.10.2012, 18:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 12
Регистрация: 10.3.2012

Репутация: нет
Всего: нет



Приветствую вас! Имеется калькулятор, состоящий из следующих частей:
  •  поле Edit, в которое вводятся опреанды и выдаётся результат
  •  кнопки операций 
  •  кнопка "равно"
  •  кнопка очистки
Операции и операнды вносятся в очередь, а после нажатия кнопки "равно" происходит обработка накопленного выражения. Вобщем, код, реализующий вычисления, следующий:
Код

void __fastcall TForm1::Operation(TObject *Sender)
{
    enum { sum = 1, sub, mul, div, intmod, intdiv, clear, equal = 9 };

    int                        tag   = ((TButton*)Sender)->Tag;
    bool                       error = false, prnths = false;

    try {
        op = StrToFloat(OpResEdit->Text);
    }
    catch(EConvertError&)
    {
        if(!OpResEdit->Text.IsEmpty())
        {
            OpResEdit->Text = "error: incorrect input";
            return;
        }
    }

    if(!OpResEdit->Text.IsEmpty())
        old = op;
    else
        op = old;
    operands.push(op);

    if(tag == equal)
    {
        try {
            res = operands.front();
            operands.pop();
            while(!operators.empty())
            {
                operation = operators.front();
                op        = operands.front();
                if((operation == '/' || operation == 'm' || operation == 'd') && !op)
                    throw EZeroDivide("error: division by zero");
                switch(operation)
                {
                    case '+': res += op;                break;
                    case '-': res -= op;                break;
                    case '*': res *= op;                break;
                    case '/': res /= op;                break;
                    case 'm': res = (int)res % (int)op; break;
                    case 'd': res = (int)res / (int)op; break;
                }
                operators.pop();
                operands.pop();
            }
        }
        catch(EZeroDivide& exc)
        {
           OpResEdit->Text = exc.Message;
           error = true;
        }
        if(!error)
            OpResEdit->Text = FloatToStr(res);
        OpLbl->Caption  = "";
        res = 0;
    }
    else
    {
        if(!operators.empty())
            prnths = ((operators.back() == '*' || operators.back() == '/') ? false : true) ;
        switch(tag)
        {
            case sum:     operators.push('+'); break;
            case sub:      operators.push('-'); break;
            case mul:      operators.push('*'); break;
            case div:       operators.push('/'); break;
            case intmod: operators.push('m'); break;
            case intdiv:   operators.push('d'); break;
        }
        if((operators.back() == '*' || operators.back() == '/') && prnths)
            OpLbl->Caption = "(" + OpLbl->Caption + FloatToStr(op) + ")" + operators.back();
        else
            OpLbl->Caption = OpLbl->Caption + FloatToStr(op) + operators.back();
        OpResEdit->Text = FloatToStr(op);
    }
    cls = true;
}


Переменные в области private:
Код

    bool                             cls;
    double                         op, old;
    double                         res;
    wchar_t                       operation;
    std::queue<double>   operands;
    std::queue<wchar_t> operators;


Код для кнопки очистки:
Код

void __fastcall TForm1::ClearBtnClick(TObject *Sender)
{
    OpResEdit->Text = "";
    OpLbl->Caption  = "";
    res = op = old = 0;
    while(!operators.empty())
    {
        operators.pop();
        operands.pop();
    }
    operands.pop();
}


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

Это сообщение отредактировал(а) Dilettante - 15.10.2012, 18:13
PM MAIL   Вверх
borisbn
Дата 16.10.2012, 08:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 18
Всего: 135



Цитата(Dilettante @  15.10.2012,  18:12 Найти цитируемый пост)
Подскажите пожалуйста, всё ли здесь корректно в части вычислений?

В части вычислений вроде всё корректно. Если позволишь, придерусь к стилю.
1) Для обработки кнопки "равно" лучше сделать отдельный обработчик, т.к. часть, отвечающая за обработку "равно" никак не связана с частью, отвечающей за обработку операций
2) В чём смысл держать double res; и wchar_t operation; членами класса ? Почему не объявить их прямо в функции-обработчике ?
3) Зачем нужно преобразование из enum'а в символ и обратно, если можно хранить очередь из enum'ом ?
4) (Необязательное) Чтобы отличать члены класса от переменных, объявленных в функции, у первых д.б. какой-нибудь признак. Иногда используют подчёркивание в конце имени, иногда префикс m_ - на твой вкус.


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
artsb
Дата 16.10.2012, 12:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2280
Регистрация: 17.7.2007
Где: центр Вселенной

Репутация: 39
Всего: 64



Цитата(borisbn @  16.10.2012,  08:56 Найти цитируемый пост)
4) (Необязательное) Чтобы отличать члены класса от переменных, объявленных в функции, у первых д.б. какой-нибудь признак. Иногда используют подчёркивание в конце имени, иногда префикс m_ - на твой вкус. 

Можно просто писать this->MyVar. Так точно не запутаешься )


--------------------
Чем отличается умный человек от мудрого?
Умный - выпутается из любой ситуации.
Мудрый - просто в неё не попадёт.
PM MAIL   Вверх
Dem_max
Дата 16.10.2012, 12:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1780
Регистрация: 12.4.2007

Репутация: 14
Всего: 39



Я так понял если вводить такое выражение
1+6*7-3/8 = ????
какое число выведет твой калькулятор ?


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
Dilettante
Дата 16.10.2012, 16:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 12
Регистрация: 10.3.2012

Репутация: нет
Всего: нет



2borisbn, artsb
Спасибо за замечания. Об отдельном обработчике для равенства я не подумал. Как-то включил его машинально к операциям. Вообще у меня изначально обработка всего поведения, связанного с полем TEdit, скопилась в одном методе.  
Насчёт очереди из символов, с одной стороны, я к ней ещё обращаюсь при выводе строки, хранящей последовательность операций: 
Код

if((operators.back() == '*' || operators.back() == '/') && prnths)
    OpLbl->Caption = "(" + OpLbl->Caption + FloatToStr(op) + ")" + operators.back();
else
    OpLbl->Caption = OpLbl->Caption + FloatToStr(op) + operators.back();
OpResEdit->Text = FloatToStr(op);

Ну а с другой - опять же, не подумал.
Совет про именование переменных класса учту.

2Dem_max
Выведет 5,75, т.к. не соблюдает приоритеты операций и считает такое: ((1+6)*7-3)/8. 

2All
Спасибо вам за внимание к моей проблеме! Попытаюсь сдать (лабораторная, как вы, возможно, догадались).
PM MAIL   Вверх
borisbn
Дата 16.10.2012, 16:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 18
Всего: 135



Цитата(Dilettante @  16.10.2012,  16:44 Найти цитируемый пост)
Насчёт очереди из символов, с одной стороны, я к ней ещё обращаюсь при выводе строки, хранящей последовательность операций: 

на здоповье. сравнивай так
Код
if((operators.back() == mul || operators.back() == div) && prnths)

а для их отображения сделай функцию перевода enum'а в символ и вызывай её
Цитата
OpLbl->Caption = OpLbl->Caption + FloatToStr(op) + op_2_char( operators.back() );

сама функция op_2_char, как ты понимаешь, будет совсем несложная ))


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
Dilettante
Дата 16.10.2012, 17:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 12
Регистрация: 10.3.2012

Репутация: нет
Всего: нет



2borisbn

Да, удачно получается  smile Стоит так и сделать. Спасибо!  
PM MAIL   Вверх
Dem_max
Дата 16.10.2012, 17:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1780
Регистрация: 12.4.2007

Репутация: 14
Всего: 39



Цитата

Выведет 5,75, т.к. не соблюдает приоритеты операций и считает такое: ((1+6)*7-3)/8. 

Ну что тогда покритикую как просил - реализация фиговая.


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
Dilettante
Дата 16.10.2012, 17:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 12
Регистрация: 10.3.2012

Репутация: нет
Всего: нет



2Dem_max

Тут вы правы. На большее не хватило. Но я надеюсь, что для моих нужд будет достаточно.  
PM MAIL   Вверх
artsb
Дата 16.10.2012, 20:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2280
Регистрация: 17.7.2007
Где: центр Вселенной

Репутация: 39
Всего: 64



Цитата(Dilettante @  16.10.2012,  16:44 Найти цитируемый пост)
Насчёт очереди из символов

Тут всё намного проще:
Код

enum 
{ 
    sum = 1, 
    sub, 
    mul, 
    div, 
    intmod, 
    intdiv, 
    clear, 
    equal = 9 
};

const char oper_str[] = 
{
    0,        // 0
    '+',    // 1
    '-',    // 2
    '*',    // 3
    '/',    // 4
    'm',    // 5
    'd',    // 6
    0,        // 7
    0,        // 8
    0        // 9
};

И теперь можно так:
Код

OpLbl->Caption = OpLbl->Caption + FloatToStr(op) + oper_str[operators.back()];

Это будет работать быстрее, чем вызов функции.
Надеюсь, идея понятна.


--------------------
Чем отличается умный человек от мудрого?
Умный - выпутается из любой ситуации.
Мудрый - просто в неё не попадёт.
PM MAIL   Вверх
borisbn
Дата 16.10.2012, 21:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 18
Всего: 135



>    Это будет работать быстрее, чем вызов функции.
Готов поспорить, что дааааааааапалеко не всегда. Сферических коней в вакууме не предлагать
 smile 


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
artsb
Дата 16.10.2012, 23:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2280
Регистрация: 17.7.2007
Где: центр Вселенной

Репутация: 39
Всего: 64



Цитата(borisbn @  16.10.2012,  21:41 Найти цитируемый пост)
Готов поспорить, что дааааааааапалеко не всегда.

Ну, смысла спорить я не вижу, т.к. тут всё очевидно, ИМХО.
При обращении к элементу массива ничего особенного не происходит. А вот при вызове функции, происходт много чего. Например, передача параметра; переключение на вызываемую функцию; работа в самой функции (скорее всего, там будет switch); возвращение значения из функции, что влечёт за собой создание временного объекта. Возможно, ещё что-то упустил. Как бы там ни было, на всё это нужно время.
Поправьте меня, если я не прав.


--------------------
Чем отличается умный человек от мудрого?
Умный - выпутается из любой ситуации.
Мудрый - просто в неё не попадёт.
PM MAIL   Вверх
borisbn
Дата 17.10.2012, 06:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 18
Всего: 135



> Поправьте меня, если я не прав.
Теоретически (как в том анекдоте) Вы правы, а практически компилятор сделает из switch'а таблицу, и заинлайнит функцию. Проверьте. Сделайте два варианта и посмотрите ассемблерный код (с включенной оптимизацией, ессно)


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
artsb
Дата 17.10.2012, 07:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2280
Регистрация: 17.7.2007
Где: центр Вселенной

Репутация: 39
Всего: 64



Цитата(borisbn @  17.10.2012,  06:24 Найти цитируемый пост)
(с включенной оптимизацией, ессно) 

Вот. Ключевой момент ) И тем не менее, даже если функция будет оптимизирована и заинлайнится, неужели простая операция с адресом (указатель на массив + смещение) будет длить дольше?

Добавлено через 2 минуты и 17 секунд
Кстати, обе операции (мой вариант и ваш вариант с функцией) будут отрабатывать очень быстро. Настолько, что разницу заметить очень тяжело.


--------------------
Чем отличается умный человек от мудрого?
Умный - выпутается из любой ситуации.
Мудрый - просто в неё не попадёт.
PM MAIL   Вверх
Dilettante
Дата 17.10.2012, 16:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 12
Регистрация: 10.3.2012

Репутация: нет
Всего: нет



Использование массива мне нравится (и кажется наиболее быстрым, т.к., наверное, O(1) не идёт из головы  smile ), хотя работу уже сдал с правками в стиле borisbn). 

borisbn, artsb, Dem_max, 
Спасибо вам за помощь и внимание к теме!  
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++ Builder"
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по С++ Builder обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Настоятельно рекомендуем заглянуть в DRKB (Delphi Russian Knowledge Base) - крупнейший в рунете сборник материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C++ Builder | Следующая тема »


 




[ Время генерации скрипта: 0.0589 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.