i am trying to make a calculator using c++, im trying to implement error handling, so if the user enters a non arithmetic operator, it will tell the user to please enter an operator, using a while loop. the problem is, even when the user enters an operator on the first run through, the while loop still executes.
I have tried not putting a space between while, and the perinthesis, also, i tried not using a variable, and just putting all the conditionals to trigger the loop.
string getop()
{
string op;
int check = 1;
cout << "Enter an operator (+ - / *): ";
cin >> op;
if ((op != "+") || (op != "-") || (op != "/") || (op != "*"))
{
check = 0;
}
while (check == 0) // while the input is not a valid operator
{
cout << "Invalid operator, please enter a valid operator: ";
cin >> op;
if ((op == "+") || (op == "-") || (op == "/") || (op == "*"))
check = 1;
}
return op;
}
the problem is, even when the user enters an operator on the first run through, the while loop still executes.
Try:
(op != "+") && (op != "-") && (op != "/") && (op != "*")
Operator || is or operator (alternative, one or another is enough). You want operator &&, which forces all conditions to be true together.
You have a logic error:
if ((op != "+") || (op != "-") || (op != "/") || (op != "*"))
this will always yield true no matter what op is.
You want:
if ((op != "+") && (op != "-") && (op != "/") && (op != "*"))
A very good practise is to name your logical events. Also, AND chaining negations is rather unintuitive (and also unreadable). So an even better alternative would be:
bool is_valid = (op == "+") || (op == "-") || (op == "/") || (op == "*");
if (!is_valid)
check = 0;
You also shouldn't use namespace std; - you can read here why.
You want to use AND (&&), not OR (||):
if ((op != "+") && (op != "-") && (op != "/") && (op != "*"))
{
check = 0;
}
Your problem is right here:
if ((op != "+") || (op != "-") || (op != "/") || (op != "*"))
{
check = 0;
}
Suppose op is assigned a value of "+", that would mean that these conditions all evaluate to true: op != "-", op != "/", op != "*".
Since you are using the OR (||) operator, check will be assigned a value of 0 if any of those conditions are true. In fact, one of those four conditions will always be true no matter what value op has.
You should use AND (&&) instead so that check is assigned 0 when all of the conditions are true:
if ((op != "+") && (op != "-") && (op != "/") && (op != "*"))
{
check = 0;
}
when you have a chain of assertions joined by &&, normally the negation consists in negate all the assertions and change all the && operators by || or viceversa.
You changed all the asserrtions, negating them, but you forgot to change the || by &&.
Look for Demorgan's theorem in Google.
Related
so I've working on an assignment converting infix format to postfix format using a stack for the operators, for the digits of the infix notation, the code worked fine, but for the operators, it doesn't work, because the stack is initially empty when I start it, so it can't go into the while loop, but I don't know how to fix this logical error.
void calculator::convertInputIntoPostfix(){
stack S;
for(int i=0;i<mInfixInput.length();i++){
if(mInfixInput[i]>='0' && mInfixInput[i]<='9'){
mPostfixOutput+=mInfixInput[i];
}
else if(isOperator(mInfixInput[i])){
while
(!S.isEmpty()
&&hasHigherPrecedenceThan(S.top(),mInfixInput[i])==true){
mPostfixOutput += S.top();
S.pop();
}
S.push(mInfixInput[i]);
}
}
while(!S.isEmpty()){
mPostfixOutput += S.top();
S.pop();
}
}
bool calculator::isOperator(int c) const
{
return ((c == '+') ||
(c == '-') ||
(c == '*') ||
(c == '/') ||
(c == '^'));
}
bool calculator::hasHigherPrecedenceThan(int aLHS, int aRHS) const
{
if ((aRHS == '+' || aRHS == '-') &&
(aLHS == '*' || aLHS == '/' || aLHS == '^')) {
return true;
}
if ((aRHS == '+' || aRHS == '-' || aRHS == '*' || aRHS == '/') &&
(aLHS == '^')) {
return true;
}
if (aLHS == '^' && aRHS == '^') {
return true;
}
return false;
}
The cases not given above(like () spaces and commas) can be ignored, and the infix is taken by input in the main. the stack is a linked list stack. with the value being an integer.
the outputs for 2+3*3*3(desired answer:233*3*+) I've been getting is 2333**+, as it is not even entering the while loop I've written, it is just storing the values into the stack and at the end outputing it.
2333**+ might be unexpected, but it isn't actually wrong, just wrongly associative.
The way you're computing precedence, you're telling the algorithm that the case where aRHS == '*' && aLHS == '*' is false, i.e. that the operator isn't left-associative. It is. Ditto for all other cases where the operators are equal, except ^, which you are wrongly making left-associative when it is right-associative.
It is customary to use a table rather than an if-else chain when determining predence in this algorithm, and to test for >=, not >, in terms of precedence.
The version of the Dijkstra Shunting-yard algorithm given in Wikipedia has this instead of your condition:
while ((there is a function at the top of the operator stack)
or (there is an operator at the top of the operator stack with greater precedence)
or (the operator at the top of the operator stack has equal precedence and is left associative))
and (the operator at the top of the operator stack is not a left bracket):
pop operators from the operator stack onto the output queue.
For example I have the following string,
if (str[i] == '(' ||
str[i] == ')' ||
str[i] == '+' ||
str[i] == '-' ||
str[i] == '/' ||
str[i] == '*')
My question is there a concise way to say if this value one of these set of values in c++?
You can search for single character str[i] in a string with your special characters:
std::string("()+-/*").find(str[i]) != std::string::npos
Not glorious because it is C instead of C++, but the C standard library is always accessible from C++ code, and my first idea as an old dinosaur would be:
if (strchr("()+-/*", str[i]) != NULL)
Simple and compact
You may use the following:
const char s[] = "()+-/*";
if (std::any_of(std::begin(s), std::end(s), [&](char c){ return c == str[i]})) {
// ...
}
It really depends on your application actually. For such a small check and depending the context, one acceptable option could be to use a macro
#include <iostream>
#define IS_DELIMITER(c) ((c == '(') || \
(c == ')') || \
(c == '+') || \
(c == '-') || \
(c == '/') || \
(c == '*') )
int main(void)
{
std::string s("TEST(a*b)");
for(int i = 0; i < s.size(); i ++)
std::cout << "s[" << i << "] = " << s[i] << " => "
<< (IS_DELIMITER(s[i]) ? "Y" : "N") << std::endl;
return 0;
}
A more C++ish way of doing it would be to use an inline function
inline bool isDelimiter(const char & c)
{
return ((c == '(') || (c == ')') || (c == '+') ||
(c == '-') || (c == '/') || (c == '*') );
}
This post might be interesting then : Inline functions vs Preprocessor macros
Maybe not "more concise", but I think this style is succinct and expressive at the point of the test.
Of course is_arithmetic_punctuation needn't be a lambda if you're going to use it more than once. It could be a function or a function object.
auto is_arithmetic_punctuation = [](char c)
{
switch(c)
{
case '(':
case ')':
case '+':
case '-':
case '/':
case '*':
return true;
default:
return false;
}
};
if (is_arithmetic_punctuation(str[i]))
{
// ...
}
Why does the compiler issue the warning: Expression results unused in the last else statement of this code?
PowerballLottery::WinningPossibility PowerballLottery::checkTicket(PowerballTicket ticket)
{
int count = 0;
if (ticket.getBall1() == getball1() || ticket.getBall1() == getball2() || ticket.getBall1() == getball3() || ticket.getBall1() == getball4() || ticket.getBall1() == getball5())
count++;
if (ticket.getBall2() == getball1() || ticket.getBall2() == getball2() || ticket.getBall2() == getball3() || ticket.getBall2() == getball4() || ticket.getBall2() == getball5())
count++;
if (ticket.getBall3() == getball1() || ticket.getBall3() == getball2() || ticket.getBall3() == getball3() || ticket.getBall3() == getball4() || ticket.getBall3() == getball5())
count++;
if (ticket.getBall4() == getball1() || ticket.getBall4() == getball2() || ticket.getBall4() == getball3() || ticket.getBall4() == getball4() || ticket.getBall4() == getball5())
count++;
if (ticket.getBall5() == getball1() || ticket.getBall5() == getball2() || ticket.getBall5() == getball3() || ticket.getBall5() == getball4() || ticket.getBall5() == getball5())
count++;
bool match = false;
if (ticket.getPowerball() == getpowerball())
match = true;
if ((count == 0) && (match == false))
return PowerballLottery::WinningPossibility::NOTWINNING;
else if ((count == 0) && (match == true))
return PowerballLottery::WinningPossibility::POWERBALL;
else if ((count == 1) && (match == true))
return PowerballLottery::WinningPossibility::ONEPLUSPOWERBALL;
else if ((count == 2) && (match == true))
return PowerballLottery::WinningPossibility::TWOPLUSPOWERBALL;
else if ((count == 3) && (match == false))
return PowerballLottery::WinningPossibility::THREE;
else if ((count == 3) && (match == true))
return PowerballLottery::WinningPossibility::THREEPLUSPOWERBALL;
else if ((count == 4) && (match == false))
return PowerballLottery::WinningPossibility::FOUR;
else if ((count == 4) && (match == true))
return PowerballLottery::WinningPossibility::FOURPLUSPOWERBALL;
else if ((count == 5) && (match == false))
return PowerballLottery::WinningPossibility::FIVE;
else ((count == 5) && (match == true));
return PowerballLottery::WinningPossibility::FIVEPLUSPOWERBALL;
}
Effectively, the code is
if ((count == 0) && (match == false))
....
else if ((count == 5) && (match == false))
return PowerballLottery::WinningPossibility::FIVE;
else
((count == 5) && (match == true)); //<- Expression results unused
return PowerballLottery::WinningPossibility::FIVEPLUSPOWERBALL;
As said from #AlexD's answer this is primarily a problem with how you had formatted the code, and that warning appears because
else ((count == 5) && (match == true));
that statement actually isn't used to do any computation stored in a result, or making a branch decision based on it.
The
return PowerballLottery::WinningPossibility::FIVEPLUSPOWERBALL;
statement is executed regardless anyways.
Reminds a bit about the famous apple OpenSSL goto fail; bug:
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
goto fail; /* MISTAKE! THIS LINE SHOULD NOT BE HERE */
Others have already pointed out the problem the compiler was warning you about.
Now let's consider the problem it didn't warn you about: your code is much more complex than there's any good reason for it to be.
In essence, the users picks and the balls chosen in the lottery (other than the power-ball) form sets. What we care about is the size of the intersection of those two sets. The C++ standard library gives us tools to make that task a lot simpler (and it looks to me like the way you've designed your PowerBallTicket class is doing more to hinder than help too):
std::set<int> lottery {
getball1(),
getball2(),
getball3(),
getball4(),
getball5()
};
std::set<int> tick {
ticket.getball1(),
ticket.getball2(),
ticket.getball3(),
ticket.getball4(),
ticket.getball5()
};
std::vector<int> matches;
std::set_intersection(lottery.begin(), lottery.end(),
tick.begin(), tick.end(),
std::back_inserter(matches));
That gives us the matches between the two. From there, we have the problem of converting the number of matches (plus whether the Powerball matched) to choose which enumeration value to return. One easy way to do that is to is an array:
WinningPossibility rets[][6] = {
{ NOTWINNING, ONE, TWO, THREE, FOUR, FIVE},
{ POWERBALL, ONEPLUS, TWOPLUS, THREEPLUS, FOURPLUS, FIVEPLUS }
};
With those in place, our return looks something like this:
return rets[ticket.getpowerball() == getpowerball()][matches.size()];
The code above points toward an improvement: instead of all those getballX() member functions, you should just store the data in a set to start with, and operate directly on those sets. In this case, it looks like you have quasi-classes, with "encapsulation" that's losing a great deal, and gaining little (probably nothing).
You can say else <statement> or else if (<expression>) <statement>; you have the expression without the if, which the compiler is doing its best with.
While reviewing code, I have come across a few if staments using ! followed by an != in the assessment e.g.
if (!(fs.ReadByte() != (byte)'D' ||
fs.ReadByte() != (byte)'I' ||
fs.ReadByte() != (byte)'C' ||
fs.ReadByte() != (byte)'M'))
{
Console.WriteLine("Not a DCM");
return;
}
Is there any reason to use a double negative over assessing positive e.g.
if ((fs.ReadByte() == (byte)'D' ||
fs.ReadByte() == (byte)'I' ||
fs.ReadByte() == (byte)'C' ||
fs.ReadByte() == (byte)'M'))
{
Console.WriteLine("Not a DCM");
return;
}
Thanks
Those two are different. The first says "None of these are not equal", the second says "any of these are equal".
If you applied the ! operator across them, you'd have to change the || to an &&:
if ((fs.ReadByte() == (byte)'D' &&
fs.ReadByte() == (byte)'I' &&
fs.ReadByte() == (byte)'C' &&
fs.ReadByte() == (byte)'M'))
{
Console.WriteLine("Not a DCM");
return;
}
I am having some troubles with my if loop.
First off I have I assigned char sign.
void evaluate_ps(istream& input)
{
char sign;
input >> sign;
cout << sign << endl;
check(sign);
}
That prints / so my sign has the value '/'
Then I go to my void check(char operation) function
void check(char operation)
{
if(operation != '-' || operation != '+' ||
operation != '*' || operation != '/')
{
return false;
}
else return true;
}
and it's returning false... WHY!!!! I can't seem to figure this out.
Thanks everyone.
This happens because you are using the || (OR) operator. When operation is / the check operation != '-' returns true. Since || is short circuited, the entire expression returns true.
Change it to && (AND):
if (operation != '-' && operation != '+' &&
operation != '*' && operation != '/')
Another way to write this is:
if (!(operation == '-' || operation == '+' ||
operation == '*' || operation == '/'))
You probably meant all your || to be &&:
if(operation != '-' && operation != '+' &&
operation != '*' && operation != '/')
Otherwise, it will always enter the if-statement since a character will always not equal one of 4 different things.
The if statement is responding to the / not equaling one of the other values
Think about "or" even in a general sense
if blue is not green or is not red or is not blue say nope
you would need to do something like the following:
if (operation != '+' && operation != '-' && operation != '/' && operation != '*') {
return false;
}
return true;
this way its like this
if blue is not green and is not red and is not blue say nope