This question already has answers here:
Evaluating arithmetic expressions from string in C++ [duplicate]
(7 answers)
Closed 9 months ago.
I would like to convert a string equation such as 10+20 or even use of numerous operators such as 10+20*5 into an answer such as 110 from a string equation.
I have currently tried looping through each char of the equation string and sorted the numbers and operators, however, I'm not able to get any further than this. Help would be much appreciated!
int calculateFromString(string equation) {
int numbers;
string operators;
// iterate through the equation string
for (int i = 0; i < equation.length(); i++) {
if (equation.charAt(i) >= '0' && equation.charAt(i) <= '9') {
numbers += int(equation.charAt(i));
}
if (equation.charAt(i) == '+' || equation.charAt(i) == '-' || equation.charAt(i) == '*' || equation.charAt(i) == '/') {
operators += equation.charAt(i);
}
}
return numbers;
}
My intended result would be:
calculateFromString("10+20*5")
= 110
I was able to get the operators from the string and store them into the operators string using:
if (equation.charAt(i) == '+' || equation.charAt(i) == '-' || equation.charAt(i) == '*' || equation.charAt(i) == '/') {
operators += equation.charAt(i);
}
However, I'm not sure how I can turn this data into an equation that can be calculated.
there is several sub problem in what you want to achieve
pseudo code:
for char in equation;
if char == number
do stuff
else if char == operation
do stuff
the number in the equation, will they only be integer ?
that's a single problem its self.
lets assume its only integer...
To test if char is a number you can check if the ascii code is a number (numbers will be between the decimal value of 48 and 57)
Or you can try/catch std::stoi(char)... if no error occurs than its a number.
(At some point you will need std::stoi anyway and try/catch error is a good practice to use)
there's a sub problem to that-> how to determine when the number ends ?
than you will have to create a sub routine to determine the math operation priorities, that won't be an easy task.
first use a std::list or std::vector to store string like that:
[number, operation, number, operation]
then i would use two std::map
one for the numbers and its index
the other one operations and its index
with the index you can determine what operation and numbers goes together
Related
As I have read, the C++ compiler initialize table with the random data, before I initialize it by myself.
I've got a program which after performing (for example) give me this output - char table.
{'D','K','2','EMPTY FIELD','1','+','EMPTY FIELD','EMPTY FIELD','3','EMPTY FIELD','/'}
Now I would like to delete whole inconvenient data like letters, and empty fields.
I'm trying to achieve this by this code, but I think it transfer it into ASCII code. Am I able to achieve this in another way ?
char wynik[20];
int j = 0;
for (int i = 0; i <20; i++)
{
if (wyjscie[i] == '+' || wyjscie[i] == '-' || wyjscie[i] == '/' || wyjscie[i] == '*' || (wyjscie[i] >-241241 || wyjscie[i] < 2141242142 ))
{
wynik[j] = wyjscie[i];
j++;
}
}
(wyjscie[i] >-241241 || wyjscie[i] < 2141242142 ) is your problem. You're confusing the integer values represented by a character and the integer codes of characters. If you want to check if a character c is between 0 and 9 you could do c >= '0' && c <= '9'.
Well currently I am re creating my own version of enigma as a little project but if you understand how the enigma machine works it has rotors which connect a character to a completely different character for example A might be connected to F or U may be connected to C and this is done three times. Currently I am getting the char for the rotor by using this function:
char getRotorOne(char i) {
if(i == 'a') {
return 'g';
}if(i == 'b') {
return 'A';
}if(i == 'c') {
return 'o';
}
The main problem with this is it takes a long time to write and it seems inefficient and I think there must be a better way. The other problem with this is on the original enigma machine there were only the 26 letters of the alphabet on this there are the 94 tapeable characters of ascii (32-126) is there any other simpler way that this can be done? If you think this question is unclear or you don't understand please tell me instead of just flagging my post, then you can help me improve my question.
Use tables! Conveniently, C string literals are arrays of characters. So you can do this:
// abc
const char* lower_mapping = "gAo";
// ABC
const char* upper_mapping = "xyz";
char getRotorOne(char i) {
if (i >= 'a' && i <= 'z') return lower_mapping[i - 'a'];
if (i >= 'A' && i <= 'Z') return upper_mapping[i - 'A'];
assert(false && "Unknown character cannot be mapped!");
}
Since chars are really just small integers, and ASCII guarantees contiguous ranges for a-z and A-Z (and 0-9) you can subtract from a given character the first one in its range (so, 'a' or 'A') to get an index into that range. That index can then be used to look up the corresponding character via a table, which in this case is just a simple hardcoded string literal.
This is an improvement on Cameron's answer. You should use a simple char array for each rotor, but as you said you want to process ASCII characters in the range 32-126, you should build each mapping as an array of 95 characters:
char rotor1[95] ="aXc;-0..."; // the 95 non control ascii characters in arbitrary order
Then you write your rotor function that way:
char getRotorOne(char i) {
if ((i < 32) || (i > 126)) return i; // do not change non processed characters
return rotor1[i - 32]; // i - 32 is in range 0 - 94: rotor1[i - 32] is defined
}
I am asking the user to input an expression which will be evaluated in postfix notation. The beginning of the expression is the variable name where the answer of the evaluated expression will be stored. Ex: A 4 5 * 6 + 2 * 1 – 6 / 4 2 + 3 * * = where A is the variable name and the equal sign means the answer to the expression will be stored in the variable A. The OUT A statement means that the number stored in the variable A will be printed out.
What I need help with is that when I input the second expression, I do not get the right answer. For example, my first expression A 4 5 * 6 + 2 * 1 – 6 / 4 2 + 3 * * = will evaluate to 153 and then when I input my second expression B A 10 * 35.50 + =, it has to evaluate to 1565.5, but it doesn't. It evaluates to 35.5. I cannot figure out why I am getting the wrong answer. Also, I need help with the OUT statement.
else if (isalpha(expr1[i]))
{
stackIt.push(mapVars1[expr1[i]]);
}
Will place the variable, or zero if the variable has not been set, onto the stack.
else if (isalpha(expr1[i]))
{
map<char, double>::iterator found = mapVars1.find(expr1[i]);
if (found != mapVars1.end())
{
stackIt.push(found->second);
}
else
{
// error message and exit loop
}
}
Is probably better.
Other suggestions:
Compilers are pretty sharp these days, but you may get a bit out of char cur = expr1[i]; and then using cur (or suitably descriptive variable name) in place of the remaining expr1[i]s in the loop.
Consider using isdigit instead of expr1[i] >= '0' && expr1[i] <= '9'
Test your code for expressions with multiple spaces in a row or a space after an operator. It looks like you will re-add the last number you parsed.
Test for input like 123a456. You might not like the result.
If spaces after each token in the expression are specified in the expression protocol, placing your input string into a stringstream will allow you to remove a great deal of your parsing code.
stringstream in(expr1);
string token;
while (in >> token)
{
if (token == "+" || token == "-'" || ...)
{
// operator code
}
else if (token == "=")
{
// equals code
}
else if (mapVars1.find(token) != mapVars1.end())
{
// push variable
}
else if (token.length() > 0)
{
char * endp;
double val = strtod(token.c_str(), &endp);
if (*endp == '\0')
{
// push val
}
}
}
To use previous symbol names in subsequent expressions add this to the if statements in your parsing loop:
else if (expr1[i] >= 'A' && expr1[i] <= 'Z')
{
stackIt.push(mapVars1[expr[i]]);
}
Also you need to pass mapVars by reference to accumulate its contents across Eval calls:
void Eval(string expr1, map<char, double> & mapVars1)
For the output (or any) other command I would recommend parsing the command token that's at the front of the string first. Then call different evaluators based on the command string. You are trying to check for OUT right now after you have already tried to evaluate the string as an arithmetic assignment command. You need to make that choice first.
I am trying to make a program generating random numbers until it finds a predefined set of numbers (eg. if I had a set of my 5 favourite numbers, how many times would I need to play for the computer to randomly find the same numbers). I have written a simple program but don't understand the outcome which seems to be slightly unrelated to what I expected, for example the outcome does not necessarily contain all of the predefined numbers sometimes it does (and even that doesn't stop the loop from running). I think that the problem lies in the logical operator '&&' but am not sure. Here is the code:
const int one = 1;
const int two = 2;
const int three = 3;
using namespace std;
int main()
{
int first, second, third;
int i = 0;
time_t seconds;
time(&seconds);
srand ((unsigned int) seconds);
do
{
first = rand() % 10 + 1;
second = rand() % 10 + 1;
third = rand() % 10 + 1;
i++;
cout << first<<","<<second<<","<<third<< endl;
cout <<i<<endl;
} while (first != one && second != two && third != three);
return 0;
}
and here is out of the possible outcomes:
3,10,4
1 // itineration variable
7,10,4
2
4,4,6
3
3,5,6
4
7,1,8
5
5,4,2
6
2,5,7
7
2,4,7
8
8,4,9
9
7,4,4
10
8,6,5
11
3,2,7
12
I have also noticed that If I use the || operator instead of && the loop will execute until it finds the exact numbers respecting the order in which the variables were set (here: 1,2,3). This is better however what shall I do make the loop stop even if the order is not the same, only the numbers? Thanks for your answers and help.
The issue is here in your condition:
} while (first != one && second != two && third != three);
You continue while none of them is equal. But once at least one of them is equal, you stop/leave the loop.
To fix this, use logical or (||) rather than a logical and (&&) to link the tests:
} while (first != one || second != two || third != three);
Now it will continue as long as any of them doesn't match.
Edit - for a more advanced comparison:
I'll be using a simple macro to make it easier to read:
#define isoneof(x,a,b,c) ((x) == (a) || (x) == (b) || (x) == (c))
Note that there are different approaches you could use.
} while(!isoneof(first, one, two, three) || !isoneof(second, one, two, three) || !isoneof(third, one, two, three))
You have a mistake in your logical condition: it means "while all numbers are not equal". To break this condition, it is enough for one pair to become equal.
You needed to construct a different condition - either put "not" in front of it
!(first==one && second==two && third==three)
or convert using De Morgan's law:
first!=one || second!=two || third!=three
Sorry, I realized that I put in all of my code in this question. All of my code equals most of the answer for this particular problem for other students, which was idiotic.
Here's the basic gist of the problem I put:
I needed to recognize single digit numbers in a regular mathematical expression (such as 5 + 6) as well as double digit (such as 56 + 78). The mathematical expressions could also be displayed as 56+78 (no spaces) or 56 +78 and so on.
The actual problem was that I was reading in the expression as 5 6 + 7 8 no matter what the input was.
Thanks and sorry that I pretty much deleted this question, but my goal is not to give answers out for homework problems.
Jesse Smothermon
The problem really consists of two parts: lexing the input (turning the sequence of characters into a sequence of "tokens") and evaluating the expression. If you do these two tasks separately, it should be much easier.
First, read in the input and convert it into a sequence of tokens, where each token is an operator (+, -, etc.) or an operand (42, etc.).
Then, perform the infix-to-postfix conversion on this sequence of tokens. A "Token" type doesn't have to be anything fancy, it can be as simple as:
struct Token {
enum Type { Operand, Operator };
enum OperatorType { Plus, Minus };
Type type_;
OperatorType operatorType_; // only valid if type_ == Operator
int operand_; // only valid if type_ == Operand
};
First, it helps to move such ifs like this
userInput[i] != '+' || userInput[i] != '-' || userInput[i] != '*' || userInput[i] != '/' || userInput[i] != '^' || userInput[i] != ' ' && i < userInput.length()
into its own function, just for the clarity.
bool isOperator(char c){
return c == '+' || c == '-' || c == '*' || c == '/' || c == '^';
}
Also, no need to check that it's no operator, just check that the input is a number:
bool isNum(char c){
return '0' <= c && c <= '9';
}
Another thing, with the long chain above, you got the problem that you will also enter the tempNumber += ... block, if the input character is anyhing other than '+'. You would have to check with &&, or better with the function above:
if (isNum(userInput[iterator])){
tempNumber += userInput[iterator];
}
This will also rule out any invalid input like b, X and the likes.
Then, for your problem with double digit numbers:
The problem is, that you always input a space after inserting the tempNumber. You only need to do that, if the digit sequence is finished. To fix that, just modify the end of your long if-else if chain:
// ... operator stuff
} else {
postfixExpression << tempNumber;
// peek if the next character is also a digit, if not insert a space
// also, if the current character is the last in the sequence, there can be no next digit
if (iterator == userInput.lenght()-1 || !isNum(userInput[iterator+1])){
postfixExpression << ' ';
}
}
This should do the job of giving the correct representation from 56 + 78 --> 56 78 +. Please tell me if there's anything wrong. :)