Форум программистов, компьютерный форум CyberForum.ru

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
Sergey_Chizhov
1 / 1 / 0
Регистрация: 21.09.2013
Сообщений: 30
#1

Калькулятор выводит неверный результат - C++

01.02.2014, 20:37. Просмотров 423. Ответов 7
Метки нет (Все метки)

Изучаю С++ по Страуструпу.
Дошел до следующей задачи(калькулятор) и "буксую", не пойму в чем дело, код с книгой сверял несколько раз.
Программа запускается, но выводит не верный результат, всегда начинающийся с "156", и то после того как введешь ещё несколько дополнительных чисел.

Будьте добры, помогите начинающему)
Буду рад любой помощи.
Библиотеку "std_lib_facilities.h" можно найти здесь: Тайна Страуструпа - std_lib_facilities.h !

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include "std_lib_facilities.h"
 
class Token{
public:
    char kind;
    double value;
    Token(char ch)    // make a Token from a char
        :kind(ch), value(0) { }    
    Token(char ch, double val)     // make a Token from a char and a double
        :kind(ch), value(val) { }
};
 
class Token_stream {
public:
    Token_stream();
    Token get();
    void putback(Token t);
private:
    bool full;
    Token buffer;
};
 
Token_stream::Token_stream()
:full(false),buffer(0)
{
}
 
void Token_stream::putback(Token t)
{
    if(full) error("putback() в полный буфере");
    buffer = t;
    full = true;
}
 
 
//-------------------------------------------------------------------------------------------
 
Token Token_stream::get()    // считывает символы и составляет лексемы использует поток cin
{
    if(full){//если в буфере есть лексема, то удаляем ее
        full=false;
        return buffer;
    }
 
    char ch;
    cin >> ch;    // note that >> skips whitespace (space, newline, tab, etc.)
 
    switch (ch) {
    case '=':    // for "print"
    case 'q':    // for "quit"
    case '(': case ')': case '+': case '-': case '*': case '/': 
    case'%':
        return Token(ch);        // let each character represent itself
 
    case '.':
    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '8': case '9':
        {    
            cin.putback(ch);         // put digit back into the input stream
            double val;
            cin >> val;              // read a floating-point number
            return Token('8',val);   // let '8' represent "a number"
        }
    default:
        error("Bad token");
    }
}
 
 
Token_stream ts;        // provides get() and putback() 
 
//-----------------------------------------------------------------------------------------------
 
 
double expression();//реализует операции + и - вызывает функции term() и get_token()
double term();//реализует операции *,/ вызывает функции primary() и get_token()
//double primary();//реализует числа и скобки, вызывает функции expression() и get_token()
 
 
double primary(){
    Token t=ts.get();
    switch(t.kind){
        case '(':
            {
                double d = expression();
                t=ts.get();
                if(t.kind!=')') error("')' expected");
                return d;
            }
        case '8':
            return t.value;
        default:
            error("ozhidaetsy pervichnoe virazhenie");
    }
}
 
int main()
try{
    cout<<"This is calculator! \nYou can used: +,-,*,/,% and (,)  \nFor print results press '=' \nFor exit press 'q'\n";
    double val=0;
    while(cin){
        Token t=ts.get();
        if(t.kind=='q') break;
        if(t.kind=='=')
            cout<<'= '<<expression()<<endl;
        else
            ts.putback(t);
        val=expression();
    }
    keep_window_open("~0");
}
catch(exception& e){
    cerr<<e.what()<<endl;
    keep_window_open("~1");
    return 1;
}
catch(...){
    cerr<<"exeption \n";
    keep_window_open("~2");
    return 2;
}
 
double expression(){
    double left=term();
    Token t=ts.get();
    while(true){
        switch(t.kind){
            case '+':
                left+=term();
                t=ts.get();
                break;
            case '-':
                left-=term();
                t=ts.get();
                break;
            default:
                ts.putback(t);
                return left;
        }
    }
}
 
double term(){
    double left=primary();
    Token t=ts.get();
    while(true){
        switch(t.kind){
            case '*':
                left*=primary();
                t=ts.get();
                break;
            case '/':
                {
                    double d=primary();
                    if(d==0) error("delenie na 0!");
                    left/=d;
                    t=ts.get();
                    break;
                }
            default:
                ts.putback(t);
                return left;
        }
    }
}
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
01.02.2014, 20:37     Калькулятор выводит неверный результат
Посмотрите здесь:

C++ Деревья, неверный результат
C++ выводит неверный ответ
C++ Сложение массивов разной длины. Неверный результат
C++ Выводит неверный результат ln2=1-1/2+1/3-1/4
При значении больше 10 выводит неверный результат C++
C++ Почему выводит неверный результат при вычислении произведения?
Метод Гаусса-Зейделя: неверный результат C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Fene4ka_
87 / 87 / 16
Регистрация: 24.01.2014
Сообщений: 1,196
01.02.2014, 23:32     Калькулятор выводит неверный результат #2
Я читаю его книгу и написал калькулятор по другому, если хочешь скину код, если найду ...
Sergey_Chizhov
1 / 1 / 0
Регистрация: 21.09.2013
Сообщений: 30
02.02.2014, 07:43  [ТС]     Калькулятор выводит неверный результат #3
Fene4ka_, скидывай, попробую разобраться)
Fene4ka_
87 / 87 / 16
Регистрация: 24.01.2014
Сообщений: 1,196
02.02.2014, 17:39     Калькулятор выводит неверный результат #4
скобки реализуешь сам, и как-то много строчек получилось там есть лишние функции, но мне было лень их убирать ...
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
#include "stdafx.h"
#include <iostream>
#include <vector>
 
using namespace std;
 
string enter(void); //вводим выражение 
string mist(string); //поиск неверных символом
string clear(void); //очищаем переменные  
bool check_point(int, string); //проверяем наличие лишних точек 
bool right_symbols(char); //проверяем правильность ввода выражения 
bool right_symbols2(char, char); //проверяем правильность ввода знаков
void record(string); //перепись выражения в структуру
void del_point(void); //удаляем лишние точки 
void point_numbers(void); //обрабатываем числа с точкой
void negative_numbers(void); //обрабатываем отрицательные числа
void grade(void); //возводим все числа в степень  
void second_order(void); //умножаем или делим числа 
void third_order(void); //складываем или вычетаем числа
void rezult(); //выводим результат
void help(void); //выводим справку 
 
struct detail
{
    vector<double> Number;//содержит числа выражения
    vector<char> symbol;//содержит знаки выражения
    vector<int> Ind;//номера знаков выражения в строке
}stTerm;
 
 
int _tmain(int argc, _TCHAR* argv[])
{
    string sTerm; //сюда будет записываться наше выражение
    short int iStart = 0; //варианты выбора
    setlocale(0, "");
    while (iStart != 3)
    {
        system("cls");
        cout<<"Введите 1 для получения справки"<<endl;
        cout<<"Введите 2 для использование калькулятора"<<endl;
        cout<<"Введите 3 для выхода"<<endl;
        cin>>iStart;
        switch (iStart)
        {
        case 1:{ //получаем справку
                help();
                break;
               }
        case 2:{ //производим вычисления
                cout<<"Введите выражение и намжите = для продолжения : ";
                sTerm = enter(); //вводим выражение
                sTerm = mist(sTerm); //переписываем массив в правильном виде
                sTerm = mist(sTerm); //вызываем два раза, так как плюсы с первого раза не всегда удаляет
                record(sTerm);//перепись выражения в структуру
                if (stTerm.Number.size() < 2) //проверяем кол-во веденных переменых, если меньше двух, то прерываем циклы
                {
                    cout<<"Неверное число переменных"<<endl;
                    system("pause");
                    break;
                }
                system("cls");
                del_point(); //удаляем лишние точки
                cout<<">";
                for (int i = 0; i < sTerm.size(); i++)
                    cout<<sTerm[i];
                point_numbers(); //обрабатываем числа с точкой
                negative_numbers(); //обрабатываем отрицательные числа
                grade();//возводим все числа в степень
                second_order(); //умножаем и делим числа
                third_order(); //складываем или вычетаем числа      
                cout<<endl<<'='<<stTerm.Number[0]<<endl;
                cout<<endl;
                system("pause");
                break;
               }
        case 3:{ //выходим из программы
                _exit(1);
                break;
               }
        default:cout<<"Неверный выбор"<<endl;
        }
        sTerm = clear(); //очищаем переменные
    }
}
 
string enter(void)
{
    char x(2); 
    string term;
    while (cin>>x) //вводим выражение
        if (x!='=') //прерываем ввод после ввода =
        {
            stTerm.Number.push_back(0); //создаем незанятые элементы вектора для последущего их заполнения
            term+=x; //записываем все в переменную типа стринг
        }
        else
            break;
    return term;
}
 
string mist(string term)
{
    string expr; //промежуточная переменная
    for (int i = 0; i < term.length()-1; i++)
    {
        //условие пропускает только определенные символы, также проверяет на следование знака за знаком(считается ошибкой) и проверяет точки
        if ((right_symbols(term[i]))&&(right_symbols2(term[i], term[i+1]))
            &&(check_point(i, term)))
             //ограничиваем ввод допустимых символом
            expr+=term[i];
    }
    //последний символ должен являться цифрой
    if ((term[term.length()-1] == '1')||(term[term.length()-1] == '2')||(term[term.length()-1] == '3')||(term[term.length()-1] == '4')||
        (term[term.length()-1] == '5')||(term[term.length()-1] == '6')||(term[term.length()-1] == '7')||
             (term[term.length()-1] == '8')||(term[term.length()-1] == '9')||(term[term.length()-1] == '0')) expr+=term[term.length()-1];
    return expr;
}
 
void record(string term)
{
    int iK = 0;
    for (int i = 0; i<term.length(); i++) //записываем нужные значение в вектора структутры
        switch (term[i])
        {
            case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '0':
            {
                //если нам попадается цифра и элемент вектора еще не был занят, то просто туда записываем цифру
                if (stTerm.Number[iK] == 0)
                    stTerm.Number[iK] = term[i]-48;
                //а если занят, то умножаем эту цифру на 10 (чтобы получить двузначное число) и прибовляем следущую цифру
                else
                    stTerm.Number[iK] = stTerm.Number[iK]*10+(term[i]-48);
                break;
            }
        default:
            {
                //если не цифра - значит записывается знак и помечается его индекс ( нужен для выполнение действий с некоторыми знаками)
                iK++;
                stTerm.symbol.push_back(term[i]);
                stTerm.Ind.push_back(i);
            }
        }
    //если остались лишние элементы в векторе - удалеяем их, чтобы не занимали память :)
    for (int i = stTerm.Number.size()-1; stTerm.Number[i] == 0.0; i--) //удаляем лишние нули из вектора чисел
        stTerm.Number.erase(stTerm.Number.begin()+i);
}
 
void grade(void)
{
    for (int i = 0; i < stTerm.symbol.size(); i++) //возводим в степень числа
        if (stTerm.symbol[i] == '^')
        {
            //возводим число в степень и записываем его в вектор
            stTerm.Number[i] = pow(stTerm.Number[i], stTerm.Number[i+1]);
            //удаляем элементы вектора знаков и цифры степени
            stTerm.Number.erase(stTerm.Number.begin()+i+1);
            stTerm.symbol.erase(stTerm.symbol.begin()+i);
            i--; //для надежности
        }
}
 
void rezult()
{
        cout<<stTerm.Number[0]<<endl;
}
 
void second_order(void)
{
    for (int i = 0; i < stTerm.symbol.size(); i++) //умножаем и делим числа
        switch (stTerm.symbol[i])
        {
        case '*':{
                    //[1]просто умножаем число на число
                    stTerm.Number[i] *=stTerm.Number[i+1];
                    //удаляем лишние элементы вектора
                    stTerm.Number.erase(stTerm.Number.begin()+i+1);
                    stTerm.symbol.erase(stTerm.symbol.begin()+i);
                    //для надежности
                    i--;
                    break;
                 }
        case '/':{
                    //читать [1]
                    stTerm.Number[i] /=stTerm.Number[i+1];
                    stTerm.Number.erase(stTerm.Number.begin()+i+1);
                    stTerm.symbol.erase(stTerm.symbol.begin()+i);
                    i--;
                    break;
                 }
        }
}
 
void third_order(void)
{
    for (int i = 0; i < stTerm.symbol.size(); i++) //умножаем и делим числа
        switch (stTerm.symbol[i])
        {
        case '+':{
                    //читать [1] в second_order()
                    stTerm.Number[i] +=stTerm.Number[i+1];
                    stTerm.Number.erase(stTerm.Number.begin()+i+1);
                    stTerm.symbol.erase(stTerm.symbol.begin()+i);
                    i--;
                    break;
                 }
        case '-':{
                    //читать [1] в second_order()
                    stTerm.Number[i] -=stTerm.Number[i+1];
                    stTerm.Number.erase(stTerm.Number.begin()+i+1);
                    stTerm.symbol.erase(stTerm.symbol.begin()+i);
                    i--;
                    break;
                 }
        }
}
 
void negative_numbers(void)
{
    for (int i = 0; i < stTerm.symbol.size(); i++) //обрабатываем отрицательные числа
    {
        //делаем отрицательным первое число [2]
        if ((stTerm.symbol[i] == '-')&&(i == 0)&&(stTerm.Ind[0] == 0))
        {
            stTerm.Number.erase(stTerm.Number.begin()+i); //завалялся лишний ноль
            stTerm.Number[i] =stTerm.Number[i]*(-1); //просто делаем число отрицательным
            //удаляем лишние элеметы вектора
            stTerm.symbol.erase(stTerm.symbol.begin()+i);
            stTerm.Ind.erase(stTerm.Ind.begin()+i);
        }
        //делаем отрицательным остальные числа, читать [2] в negative_numbers()
        if ((stTerm.symbol[i] == '-')&&(i > 0))
            if (stTerm.Ind[i-1]+1 == stTerm.Ind[i])
            {
                stTerm.Number.erase(stTerm.Number.begin()+i);
                stTerm.Number[i] =stTerm.Number[i]*(-1);
                stTerm.symbol.erase(stTerm.symbol.begin()+i);
                stTerm.Ind.erase(stTerm.Ind.begin()+i);
            }
    }
}
 
string clear(void)
{
    stTerm.Number.erase(stTerm.Number.begin(), stTerm.Number.end()); //очищаем вектор чисел
    stTerm.symbol.erase(stTerm.symbol.begin(), stTerm.symbol.end()); //очищаем вектор знаков
    stTerm.Ind.erase(stTerm.Ind.begin(), stTerm.Ind.end()); //очищаем вектор индексов
    return "";
}
 
void help(void)
{
    system("cls");
    cout<<"Используемая версия программы : 0.2а."<<endl;
    cout<<"Калькулятор умеет обрабатывать длинные выражения с возведением в степень, делением, умножением, сложением, вычитанием."<<endl;
    cout<<"Калькулятор умеет обрабатывать отрицательные числа."<<endl;
    cout<<"Калькулятор умеет обрабатывать дробные числа"<<endl;
    cout<<"Калькулятор пока-что не умеет обрабатывать скобки."<<endl;
    cout<<"В выражении типа <<05+2=>> <<0>> считываться не будет."<<endl;
    cout<<"Для правильной работы калькулятора при делении используйте значок '/', а не '\\'."<<endl<<endl<<endl;
    system("pause");
}
 
void del_point(void)
{
    //удаляем затерявшиеся точки, для надежности
    for (int i = 0; i < stTerm.symbol.size()-1; i++)
        if (((stTerm.symbol[i] == '.')||(stTerm.symbol[i] == '.'))&&((stTerm.symbol[i+1] == '.')||(stTerm.symbol[i+1] == ',')))
        {
            stTerm.Number.erase(stTerm.Number.begin()+i+2);
            stTerm.symbol.erase(stTerm.symbol.begin()+i+1);
            stTerm.Ind.erase(stTerm.Ind.begin()+i+1);
            i--;
        }
}
 
void point_numbers(void)
{
    double dNum = 0; //числитель
    double dDenum = 1; //знаменатель
    int iNumb = 0; //число символов после запятой
    int iK; //содержит промежуточное значение
    for (int i = 0; i < stTerm.symbol.size(); i++)
        if ((stTerm.symbol[i] == '.')||(stTerm.symbol[i] == ','))
        {
            iK = stTerm.Number[i+1]; //записываем число после запятой
            while (iK!=0) //находим кол-во цифр после запятой, для знаменателя
            {
                iK /= 10;
                iNumb++; //тут кол-во цифр
            }
            dNum = pow(10.0, iNumb)*stTerm.Number[i]+stTerm.Number[i+1]; //высчитываем числитель дроби
            dDenum = pow(10.0 , iNumb); //знаменатель дроби
            stTerm.Number[i] = dNum / dDenum; //получаем значение
            //удаляем лишнии элементы
            stTerm.Number.erase(stTerm.Number.begin()+i+1);
            stTerm.symbol.erase(stTerm.symbol.begin()+i);
            stTerm.Ind.erase(stTerm.Ind.begin()+i);
            i--; //для надежности
            iNumb = 0; //обнуляем переменную для последущих вычислений
        }
}
 
bool check_point(int k, string term)
{
    //если символ точка или запятая ( после второго по счету символа ) то ...
    if (((term[k] == '.')||(term[k] == ','))&&(k>1))
        for (int i = k-1; i > 0; i--)
        {
            //движемся назад и если натыкаемся на символ-знак действия, то все нормально - записываем символ в стринг
            if ((term[i] == '+')||(term[i] == '-')||(term[i] == '/')||(term[i] == '*')||(term[i] == '^')) 
            {
                return true;
                break;
            }
            //а если встречаем точку или запятую, то незаписываем в стринг
            else if ((term[i] == '.')||(term[i] == ',')) 
            {
                return false;
                break;
            }
        }
    else return true;
    //тоже самое, что и выше, но сравнивает исключительно с предыдущим символом
    if (((term[k] == '.')||(term[k] == ','))&&(k > 0)&&((term[k-1] == '+')||(term[k-1] == '-')||(term[k-1] == '/')||(term[k-1] == '*')||
        (term[k-1] == '^'))) return false;
    //если самый первый символ точка или запятая, то незаписываем его ( первым символом должна быть цифра )
    if (((term[0] == '.')||(term[k] == ','))&&(k == 0)) return false;
}
 
bool right_symbols(char symbol)
{
    //список символом, которые пройдут проверку :)
    if ((symbol == '1')||(symbol == '2')||(symbol == '3')||(symbol == '4')||(symbol == '5')||(symbol == '6')||(symbol == '7')||
        (symbol == '8')||(symbol == '9')||(symbol == '0')||(symbol == '+')||(symbol == '-')||(symbol == '*')||(symbol == '/')||
        (symbol == '%')||(symbol == '^')||(symbol == '.')||(symbol == ','))
            return true;
    else    return false;
}
 
bool right_symbols2(char symbol, char symbol2)
{
    //список знаков, которые пройдут проверку ( некоторые знаки не должны следовать друг за другом )
    if (((symbol == '+')||(symbol == '-')||(symbol == '*')||(symbol == '/')||(symbol == '%'))&&
        ((symbol2 == '+')||(symbol2 == '-')||(symbol2 == '*')||(symbol2 == '/')||(symbol2 == '%')))
        return false;
    else if ((symbol == '^')&&(symbol2 == '^'))
        return false;
    else
        return true;
}
Добавлено через 1 минуту
даже с комментариями писал пол года назад
Sergey_Chizhov
1 / 1 / 0
Регистрация: 21.09.2013
Сообщений: 30
03.02.2014, 06:09  [ТС]     Калькулятор выводит неверный результат #5
Fene4ka_, СПАСИБО)
Почему у меня(Visual C++ 2008) компилятор в первой строке (#include "stdafx.h") пишет ошибку No such file directory?
Пробовал так тоже "stdafx", <stdafx.h>, <stdafx>
Enotniy
96 / 95 / 14
Регистрация: 15.01.2014
Сообщений: 283
03.02.2014, 06:38     Калькулятор выводит неверный результат #6
Sergey_Chizhov, просто уберите, скорее всего в этом файле ничего нет, и он не нужен.
Fene4ka_
87 / 87 / 16
Регистрация: 24.01.2014
Сообщений: 1,196
03.02.2014, 16:54     Калькулятор выводит неверный результат #7
Sergey_Chizhov, у меня visual studio 2013, этот файлик создается автоматически средой разработки и хранится в папке проекта, просто введите #include " , и если его там не будет, то он вам не нужен
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
04.02.2014, 07:47     Калькулятор выводит неверный результат
Еще ссылки по теме:

Проверка ввода и неверный результат C++
C++ Функция перемножения матриц выдает неверный результат
Неверный результат транспонирования матрицы C++
Почему выводит неверный результат? C++
C++ Неверный результат _getch()

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Sergey_Chizhov
1 / 1 / 0
Регистрация: 21.09.2013
Сообщений: 30
04.02.2014, 07:47  [ТС]     Калькулятор выводит неверный результат #8
Всем спасибо!
Yandex
Объявления
04.02.2014, 07:47     Калькулятор выводит неверный результат
Ответ Создать тему
Опции темы

Текущее время: 23:28. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru