How to reduce logic expressions? - c++

{
ans += (a[i] > a[j]) != (b[i] > b[j]);
//ans += ((a[i] > a[j]) && (b[j] > b[i])) || ((a[j] > a[i]) && (b[i] > b[j]));
}
What you see above is a snippet I took from some where. There are two logic expressions. Supposedly, the one commented out is the same as the one not commented out.
How do you get from:
((a[i] > a[j]) && (b[j] > b[i])) || ((a[j] > a[i]) && (b[i] > b[j]))
to something like this
(a[i] > a[j]) != (b[i] > b[j])
Are there any guides or books for these kind of logic expression simplifications?

This is actually very simple.
With (a[i] > a[j]) != (b[i] > b[j]), what we're saying is that this will only be true when the relationship to a[i] and a[j] is the opposite of the relationship from b[i] to b[j]. For this to hold then, if a[i]>a[j] is true, then b[i]>b[j] is false, which means that b[j]>b[i] is true. This means that when a[i]>a[j] is true, b[j]>b[i] is true, and it also means the inverse - when a[j]>a[i] is true, then b[i]>a[j] as well.
Another way of saying all of that is ( (a[i]>a[j]) && (b[j]>a[i]) ) || ( (a[j]>a[i]) && (b[i]>b[j]) . That boolean logic will be true only in the same cases where ( (a[i] > a[j]) ) != (b[i] > b[j]) is true.
As another example, consider when both a[i] > a[j] and b[i] > a[j] . You'll see that the first you posted is false in this condition, because the two terms on either side of the != evaluate to true, meaning the != evaluates to false. This case also causes the second statement to resolve to false because you don't have either of the two terms around the || evaluating to true, they both evaluate to false.
Lastly, this question looks like homework to me - if it is you should use the appropriate tag.
However, this all ignores the possibilities of a[i] == a[j] or b[i] == b[j], which another answer to this question demonstrates can cause the two statements to not evaluate to the same thing. But if you assume that the two cannot be equal, then the two statements from your question will be the same, following the logic demonstrated above.

The code you posted is right if you assume that
!(p > q) == (p < q)
Meaning that for some reason, you're ignoring equality.
With this in mind, let's say that:
a1 = a[i]
a2 = a[j]
b1 = b[i]
b2 = b[j]
Then you have:
ans += ((a1 > a2) && (b2 > b1)) || ((a2 > a1) && (b1 > b2));
Which, since we're ignoring equality, is the same as:
ans += ((a1 > a2) && !(b1 > b2)) || (!(a1 > a2) && (b1 > b2));
If you take a closer look, you'll see that the expressions are repeated, so they can be simplified:
A = a1 > a2
B = b1 > b2
Then:
ans += (A && !B) || (!A && B);
Which means either A or B, but no both
This is a known boolean operation called XOR, which in your case is the same as different (!=)
Therefore:
ans += A != B;
And expanding:
ans += (a1 > a2) != (b1 > b2)
So:
ans += (a[i] > a[j]) != (b[i] > b[j])
Hope it's clear now.

These expressions are not equivalent.
For example, when a[i] == a[j] and b[i] > b[j], the first expression gives...
(a[i] > a[j]) != (b[i] > b[j]);
false != true
true
...while the second one gives:
((a[i] > a[j]) && (b[j] > b[i])) || ((a[j] > a[i]) && (b[i] > b[j]));
(false && false) || (false && true)
false || false
false

Let's take this:
((a[i] > a[j]) && (b[j] > b[i])) || ((a[j] > a[i]) && (b[i] > b[j]))
and call it this, for simplicity:
(w > x) && (y > z) || (x > w) && (z > y)
which is NOT logically equivalent to:
(w > x) && (y > z) || !(w > x) && !(y > z)
because they could be equal, but it is to:
(w > x) && (y > z) || !(w >= x) && !(y >= z)
So you could simplify it to (w > x) == (y > z) or, alternatively, to (w > x) != (z >= y).

Related

How to make a loop to determine if 2 numbers belong in a given range

I am having problems making a loop which stops when both x and y are in the range/interval [0,1] in c++.
double x;
double y;
while(condition)
{
if(x < 0)
{
x = -x;
}
else
{
x = 2 - x;
}
if(y < 0)
{
y = -y;
}
else
{
y = 2 - y;
}
}
This method with 2 loops works:
while((x < 0) || (x > 1)) {do sth}
while((y < 0) || (y > 1)) {do sth}
This doesn't work:
while(!((x >= 0) && (x <= 1)) && !((y >= 0) && (y <= 1))) {do sth}
And this doesn't work either:
while(((x < 0) || (x > 1)) && ((y < 0) || (y > 1))) {do sth}
This makes an infinite loop (in my case):
while(((x < 0) || (x > 1)) || ((y < 0) || (y > 1))) {do sth}
Note: {do sth} changes x and y if needed so they will eventually go in that interval (same as in the first block of code).
Note 2: By doesn't work I mean it never goes in the loop when x is in the interval and y < 0 (and some other cases).
while ( !( (x>=0 && x<=1) && (y>=0 && y<=1) ) ) should be the combined conditional check.
I'd go for a dedicated function with a speaking name: so you can still understand your code in a couple of weeks :-), e.g.
auto check_outside_interval_0_1 = [] (double const a) {
return a < 0.0 or 1.0 < a;
};
while( check_outside_interval_0_1(x) or
check_outside_interval_0_1(y) ) {
// ... do your things here
}

How to have an if() split by && and not ||

I'm trying to do something like this in c++
If x is equal to either a or b or c
and y is equal to either d or e or f
and z is equal to either g or h or i, it would turn true and execute the code
I am a bit lost in this
if(x==a||x==b||x==c && y==d||y==e||y==f && z==g||z==h||z==i){
// Do x
}
Just use && and ||, with parentheses to make the grouping clear.
if ((x == 'a' || x == 'b' || x == 'c')
&& (y == 'd' || y == 'e' || y == 'f')
&& (z == 'g' || z == 'h' || z == 'i')) {
// execute code
}
If you look at C++ operator precedence you'll find that && has higher precedence than ||.
That means that your if statement
if(x==a||x==b||x==c && y==d||y==e||y==f && z==g||z==h||z==i)
is the same as
if (x == a || x == b || (x == c && y == d) ||
y == e || (y == f && z == g) ||
z == h || z == i)
By using parentheses, you can change it to work the way you want:
if ((x == a || x == b || x == c) &&
(y == d || y == e || y == f) &&
(z == g || z == h || z == i))
It is a straightforward translation from what you said to C++ code:
if ((x == a || x == b || x == c) &&
(y == d || y == e || y == f) &&
(z == g || z == h || z == i))
{
}
Most real programs don't have conditionals this complex. Split up your logic into logical tests.
From the previous answers, the important point is that in C++, you missed that the AND operator && has a higher operator precendence than the OR operator ||.
This can be compared to how the multiplicative operators *, /, % of numbers have higher precedence than additive operators + and - in algebra.
Regroup the parathetheses so you have these three requirements of what x, y, and z have to be, and the statement is true when all three are correct. (Technically, this is called a product of sums form, as the if statement requires the truth of all three smaller statements (the AND), where each of the smaller statement uses only OR statements.).
if((x==a||x==b||x==c) && (y==d||y==e||y==f) && (z==g||z==h||z==i)){
// Do x
}
Your original code would be equivalent to
if(x==a || x==b || (x==c && y==d) || y==e || (y==f && z==g) || z==h || z==i){
// Do x
}
For larger if-statements, you can also use newlines but of course that will take up more lines.
if((x==a||x==b||x==c)
&& (y==d||y==e||y==f)
&& (z==g||z==h||z==i)
&& ... other conditions)){
// Do x
}
If you do not want such cumbersome and long if-statement notation, you can consider breaking into logical tests (the if-condition is the "product" of the logical tests), namely
bool a1 = (x==a||x==b||x==c);
bool a2 = (y==d||y==e||y==f);
bool a3 = (z==g||z==h||z==i);
bool a4 ...
if (a1 && a2 && a3 && a4 && ..) {
// Do x
}
Try using parentheses to separate your questions:
if( (condA || condB || condC) && (condD || condE || condF) && (...)) and so on.
(condA = condition A)
Going a little overboard here (but just a bit):
if (element_of(x, {a, b, c}
&& element_of(y, {d, e, f})
&& element_of(z, {g, h, i}))
{
foo();
}
with element_of defined as:
template <class T>
auto element_of(const T& element, std::initializer_list<T> list) -> bool
{
return std::find(list.begin(), list.end(), element) != list.end();
}
Or a even a little bit more overboard (this is just for fun, I don't recommend it):
if (Elem{x}.element_of({a, b, c})
&& Elem{y}.element_of({d, e, f})
&& Elem{z}.element_of({g, h, i}))
{
foo();
}
with Elem:
template <class T> struct Elem
{
T element;
auto element_of(std::initializer_list<T> list) -> bool
{
return std::find(list.begin(), list.end(), element) != list.end();
}
};
template <class T> Elem(T) -> Elem<T>;

What is equivalent to "!((x > y) && (y <= 0))"

What is the equivalent to the condition:
!((x > y) && (y <= 0))
Is it:
!(x > y) && !(y <= 0)
(x <= y) || (y > 0)
(x < y) || (y > 0)
After initializing the variables to make them into y = -3 and x = -3 I was able to isolate only the second one to display the same results as the first. Does this mean that this is the only one equivalent to it?
How exactly do you use truth tables or the "De Morgan's Law"?
I believe its the second one : (x <= y) || (y>0)

Best way to format the conditional checks in "if" statement

This code looks dirty and I can't figure out how to format it so that I can read it, understand it, and look clean at the same time.
if(center==2 && ((((y-height/2)==j) && ((x+width/2)==i)) || (((y+height/2)==j) && ((x+width/2)==i))))
regenerateDot(i+1, j, dots);
Any suggestions?
I would break down the boolean expressions into variables named for readability. Something like:
bool isCentered = center == 2;
bool inLowerRegion = (y-height/2) == j && (x+width/2) == i;
bool inUpperRegion = (y+height/2) == j && (x+width/2) == i;
bool inEitherRegion = inLowerRegion || inUpperRegion;
if (isCentered && inEitherRegion) {
regenerateDot(i+1, j, dots);
}
Consider refactoring. You could put sub expressions into their own functions, thus naming their purpose.
For example:
if (IsCentered(center) && IsInsideLower(y, j, i) && IsInsideUpper(y, j, i))
regenerateDot(i + 1, j, dots);
Note that in the above example the function names might be bogus (I haven't really attempted to understand what the purpose of the code is), but you should get the picture.
Almost all the parenthesis are redundant... and adding some whitespace it becomes:
if(center == 2 &&
(y - height/2 == j && x + width/2 == i ||
y + height/2 == j && x + width/2 == i))
regenerateDot(i+1, j, dots);
For something complicated I'd probably break it down into what each condition (grouped by shared &&) is trying to signify and assign it to a sensible variable name.
At most you can remove extra braces, add some spaces and put the logical partitions in different lines as,
if(center == 2 &&
(((y - height/2) == j || (y + height/2) == j) && (x + width/2) == i))
{
regenerateDot(i+1, j, dots);
}
Edit: You have one redundant condition (x + width/2) == i which I have optimized here.
This is the same as the code you posted:
if( center == 2 )
{
if( (x+width/2) == i )
{
if( (y-height/2) == j ) || (y+height/2) == j ) )
{
regenerateDot(i+1, j, dots);
}
}
}
Re-ordering it would give something like :
if (center==2 && (i-x)==(width/2) && abs(j-y)==(height/2))
regenerateDot(i+1, j, dots);
I would do it like this
if (2 == center &&
(((y - height/2) == j && (x + width/2) == i) ||
((y + height/2) == j && (x + width/2) == i))
)
{
regenerateDot(i + 1, j, dots);
}

What is wrong with my logic?

if(location[0] <= 'H' || location[0] >= 'A'
&& location[1] <= 8 || location[1] >= 1)
I am checking to see if the first indice is between 'A' and 'H' and the second indice is between 1 - 8.
so the argument would = 1 if the user entered { A, 1 }
-1 if the user entered { J, 1 }
And (&&) has higher precedence than or (||), so to express what you want you need:
if ((location[0] <= 'H' || location[0] >= 'A') && (location[1] <= 8 || location[1] >= 1))
Otherwise what's happening is that it does the equivalent of this:
if (location[0] <= 'H' || (location[0] >= 'A' && location[1] <= 8) || location[1] >= 1)
Which is clearly not what you intended.
You can put as many expressions in the condition as you want, but you must remember the precedence rules; I suggest always using extra parentheses for clarity.
As Jeremiah has pointed out in the comments, the condition still wouldn't be doing what you wanted -- you are asking if something is in a given range by checking if it's either less than the upper bound or greater than the lower bound (this covers all input), when you intended to check whether the input was both larger than the lower bound and smaller than the upper:
if (location[0] <= 'H' && location[0] >= 'A' && location[1] <= 8 && location[1] >= 1)
In this case, since the operators are all &&, no extra parentheses are needed, though you can add them for extra clarity.
You need &&s not ||s. For example: 'Z' >= 'A' || 'Z' <= 'H' is true.
if(location[0] <= 'H' && location[0] >= 'A' && location[1] <= 8 && location[1] >= 1)
While not necessary in this case, you should group your logic together with parenthesis (and if they were ||s you would have to for it to work as expected):
if((location[0] <= 'H' && location[0] >= 'A') && (location[1] <= 8 && location[1] >= 1))
Add parenthesis to group the conditions:
if( (location[0] <= 'H' || location[0] >= 'A') && (location[1] <= 8 || location[1] >= 1))
If location[0] was equal to 'J' (definitely NOT between 'A' and 'H'), your if-clause would be TRUE because even though location[0] <= 'H' is FALSE, location[0] >= 'A' is TRUE and you are using || (OR). The problem is that you are using || (OR) instead of && (AND). You need to use all && (AND) in the if-clause.
&& has higher precedence than ||. So, you may want to write it as
if((location[0] <= 'H' || location[0] >= 'A') && (location[1] <= 8 || location[1] >= 1))
If you already tried this, please tell what error you got
Sorry guys, new here. I should have posted my entire method. Thank you for explaining the precedence of the operators, but my issue was that I was comparing a char with an int. All I needed to do was put ' ' around my numbers.
void GameBoard::enterShips()
{
char location[2];
int ships = 0;
int count = 1;
while( ships < NUM_SHIPS )
{
cout << "Enter a location for Ship " << count << ": ";
cin >> location[0];
cin >> location[1];
cout << endl;
if((location[0] <= 'H' && location[0] >= 'A') && (location[1] <= '8' && location[1] >= '1'))
{
location[0] = location[0] - 64;
location[1]--;
Grid[location[0]][location[1]] = SHIP;
ships++;
count++;
}
else
{
cout << "Wrong coordinates entered. Try again." << endl << endl;
}
}
}
As you can see in this operator precedence table, && is #13. It's higher up than ||, which is #14.
Therefore:
if(location[0] <= 'H' || location[0] >= 'A'
&& location[1] <= 8 || location[1] >= 1)
Is equivalent to:
if(location[0] <= 'H' || (location[0] >= 'A'
&& location[1] <= 8) || location[1] >= 1)
You want:
if((location[0] <= 'H' || location[0] >= 'A') &&
(location[1] <= 8 || location[1] >= 1))
Or even better:
if(((location[0] <= 'H') || (location[0] >= 'A')) &&
((location[1] <= 8) || (location[1] >= 1)))
I always put brackets around everything except when */ and +- are concerned. Even if you memorize the table, you shouldn't assume others do.
It helps code readability and helps prevent bugs... even compiler bugs! Triple bonus. :)
EDIT: Ah, you want ALL of them to be true. Just use all &&s, then! This works:
if(((location[0] <= 'H') && (location[0] >= 'A')) &&
((location[1] <= 8) && (location[1] >= 1)))