Boolean rules are bugging me - if-statement

I just encountered a propably simple problem with booleans
If I have an if statement like this one: !(!A && !B) && B, how does it exactly go?
I thought it was the same as A && B (inverts the conditions inside the brackets), but it obviously wasn't.. which is bugging me
So, would someone like to elaborate how it really goes because I think I'm missing something here?

!(!A && !B) && B is the sams as (A || B) && B you forgot to invert the and to or. Which in turn btw is just B.

!(!A && !B) = (A || B)
so
!(!A && !B) && B = (A || B) && B = A && B || B = B
The final result is simply B

Unfortunately, in general case you cannot use logic identities in programming as you do that at discrete mathematics class.
As it was mentioned by HashPsi and Bas van Stein, from the logical point of view your expression is equivalent to B. In the real world you can have the following code:
def A():
throw StupidException()
def B():
return True
!(!A() && !B()) && B() # throws exception
B() # returns True
So technically your expression differs significantly from just B. You can argue that this is very specific example, but in practice most of your functions have some side effects, so in general you can never assume that mathematical logic works for boolean expressions.
As a real-world example where ordering of boolean expressions matters, you can consider a following idiomatic C++ code:
if (foo && foo->bar()) {do something}
The code above would check that foo is not null before calling bar method. If you just rearrange that expression, you'll get a crush:
if (foo->bar() && foo) {do something}
If foo==nullptr, foo->bar will cause termination of program, since foo->bar() will try to be called before check of foo value.

Related

Is there anything from the standard library or boost that facilitates conditionally executing a function?

I am refactoring a function with too many if-else's, something like the following but more complicated. Some major characteristics of this function are:
It bails out early for many pre-conditions (e.g., condition1() and condition2()).
It only does some meaningful stuff on very specific scenarios (e.g., doA() and doB()). (Oh yeah, the beauty of temporary bug fixing!)
Some pre-conditions may or may not be independent of additional conditions (e.g., condition3/4/5/6()).
retT foo() { // total complexity count = 6
if (!condition1()) { // complexity +1
return retT{};
}
if (!condition2()) { // complexity +1
return retT{};
}
if (condition3()) { // complexity +1
if (condition4() || condition5()) { // complexity +2
return doA();
}
else if (condition6()) { // complexity +1
return doB();
}
}
return retT{};
}
The goal is to call out those actual works on their precise conditions rather than leaving them vulnerable to the change of the if-else structure in foo(). More specifically, I would like to turn foo() into something like this:
retT foo() { // total complexity count = 4
ConditionalCommand<retT> conditionalDoA{doA};
conditionalDoA.addCondition(condition1());
conditionalDoA.addCondition(condition2());
conditionalDoA.addCondition(condition3());
conditionalDoA.addCondition(condition4() || condition5()); // complexity +1
ConditionalCommand<retT> conditionalDoB{doB};
conditionalDoB.addCondition(condition1());
conditionalDoB.addCondition(condition2());
conditionalDoB.addCondition(condition3());
conditionalDoB.addCondition(!(condition4() || condition5())); // complexity +2
conditionalDoB.addCondition(condition6());
for (auto& do : {conditionalDoA, conditionalDoB}) {
if (do()) { // complexity +1
return do.result();
}
}
return retT{};
}
This makes the implementation more linear and the conditions for performing a particular work more explicit. I understand that it would be equivalent to just creating a first-level if-clause for each work with all the added conditions listed, but the above code would:
reduce our internal complexity measurement (if-else, logical operators, and ternary based, as illustrated in the code comments),
prevent future intrusion into the first-level if-clauses by a new developer, for example, who wants to doC() instead of doA() if condition7() is true, and
allow me to refine each work's conditions independently of those of the other works (recall that some conditions might be depending on each other).
So the question is, is there any existing std or boost utility that does what ConditionalCommand does so I don't need to reinvent the wheel?
Edit: conclusion at the top, frame challenge below.
Back to the original question, is there anything existing in std or boost to do what ConditionalCommand does?
OK, if you're really not worried about the fact that this design violates your own stated requirements, the answer is: NO. Nothing does exactly this.
However, you could just write something like
std::array condA { condition1(), condition2(), condition3(),
(condition4() || condition5()) };
if (std::ranges::all_of(condA, std::identity{})) doA();
if (std::ranges::all_of(
std::initializer_list<bool>{
condition1(), condition2(), condition3(),
(condition4() || condition5()),
condition6()
},
std::identity{})
)
doB();
or whatever takes your fancy. You're only suggesting a very thin convenience layer over this logic.
This makes the implementation more linear
Between perfectly linear control flow and a perfectly linear data structure, I don't really see any advantage either way on this criterion.
the conditions for performing a particular work more explicit
If by "more explicit" you mean "more declarative", then I guess so. You've hidden everything that is actually going on inside some mystery templates though, so it had better be very clear, intuitive and well documented.
reduce our internal complexity measurement (if-else, logical operators, and ternary based, as illustrated in the code comments),
Your "internal complexity measurement" is, frankly, stupid. If you optimize for a bad objective, you'll get a bad result.
Here you have very obviously increased overall complexity, increasing the learning curve for new developers, making the relationship between conditions and their consequences less clear and control flow much harder to debug.
But you've done it in a way that your "internal complexity measurement" chooses to ignore, so it looks like an improvement.
Although I dislike cyclomatic complexity as a broad measure, if yours is genuinely so much higher than shown in the question that refactoring is required - I'd still try just refactoring the procedural code before I considered your proposal.
prevent future intrusion into the first-level if-clauses by a new developer, for example, who wants to doC() instead of doA() if condition7() is true
Just write unit tests for every combination of your 7 conditions (or a single test that runs every permutation) and let your junior developer find out for themselves when the CI server complains about their branch.
You're not helping them get less junior by obfuscating your code like this, you're trying to insulate yourself from their mistakes in a way that doesn't actually help them improve.
Also, the original control flow may even have bugs in them
In that case you should definitely be writing test cases first! You're talking about refactoring code you don't trust in a way that violates your own stated requirements with no way to validate the result.
allow me to refine each work's conditions independently of those of the other works (recall that some conditions might be depending on each other).
If you really want a less error-prone way of organizing this, these condition inter-dependencies should be encoded explicitly. At the moment you can still break everything by adding conditions in the wrong order.
Further, you're currently executing all conditions unconditionally except for the short-circuit evaluation of conditions 4 & 5. Is this even well-defined? Is it guaranteed to remain well-defined?
Still further, you're now evaluating each condition multiple times, once for each possible action.
If you really must encode this in data rather than code, it could be something like an explicit dependency graph (so condition2 depends-on condition1 and is never executed unless that dependency evaluates to true). Then you can have multiple leaf actions attached to the same graph, and don't need any redundant re-evaluations.
To be fair, implementing this is a pain, but at least it satisfies your dependency requirement.
I agree with all the others that your attempt is just hiding complexity under a questionably more readable blanked. I find it much more unreadable than the original.
I think your only hope is to look at the original code and play untangle with it.
In your simplified example you have more return statements than possible returned values, and I bet in the original too, you have far more returns than possible returned values. So why don't you simply make a map (with pen and paper) of what condition leads to what return value?
Taking your simple example,
retT{} is returned only if !c1 || !c2 || !c3 || (!c4 && !c5 && !c6)
doA() is returned only if c1 && c2 && c3 && (c4 || c5)
doB() is returned only if c1 && c2 && c3 && c6
Notice that the first boolean can be re-written, using De Morgan laws, like !(c1 && c2 && c3 && (c4 || c5 || c6)).
Follows the observation that the only important booleans are actually these:
bool b1 = c1 && c2 && c3;
bool b2 = c4 || c5;
bool b3 = c6;
You can then rewrite your logic as
doA() is returned only if b1 && b2, call it p1
doB() is returned only if b1 && b3, call it p2
retT{} is returned only if !(b1 && (b2 || b3)) = !((b1 && b2) || !(b1 && b3)) = !(b1 && b2) && !(b1 && b3) = !p1 && !p2
the last sequence of equalities is the verification that all branches indeed lead to a return (otherwise the code would be erroneous).
With the above in mind (and on paper) the code can be simplified like this:
bool b1 = c1 && c2 && c3;
bool b2 = c4 || c5;
bool b3 = c6;
if (b1) {
if (b2) {
return doA();
}
if (b3) {
return doB();
}
}
return retT{};
or, if you are really scared about the time needed to compute the booleans, you can compute than "lazily":
bool b1 = c1 && c2 && c3;
if (b1) {
bool b2 = c4 || c5;
if (b2) {
return doA();
}
//bool b3 = c6;
if (/*b3*/c6) {
return doB();
}
}
return retT{};

Else keyword in non void function in C++ [duplicate]

I am always in the habit of using if, else-if statement instead of multiple if statements.
Example:
int val = -1;
if (a == b1) {
return c1;
} else if (a == b2) {
return c2;
} ...
...
} else {
return c11;
}
How does it compare to example 2:
if (a == b1) {
return c1;
}
if (a == b2) {
return c2;
}
....
if (a == b11) {
return c11;
}
I know functionality wise they are the same. But is it best practice to do if else-if, or not? It's raised by one of my friends when I pointed out he could structure the code base differently to make it cleaner. It's already a habit for me for long but I have never asked why.
if-elseif-else statements stop doing comparisons as soon as it finds one that's true. if-if-if does every comparison. The first is more efficient.
Edit: It's been pointed out in comments that you do a return within each if block. In these cases, or in cases where control will leave the method (exceptions), there is no difference between doing multiple if statements and doing if-elseif-else statements.
However, it's best practice to use if-elseif-else anyhow. Suppose you change your code such that you don't do a return in every if block. Then, to remain efficient, you'd also have to change to an if-elseif-else idiom. Having it be if-elseif-else from the beginning saves you edits in the future, and is clearer to people reading your code (witness the misinterpretation I just gave you by doing a skim-over of your code!).
What about the case where b1 == b2? (And if a == b1 and a == b2?)
When that happens, generally speaking, the following two chunks of code will very likely have different behavior:
if (a == b1) {
/* do stuff here, and break out of the test */
}
else if (a == b2) {
/* this block is never reached */
}
and:
if (a == b1) {
/* do stuff here */
}
if (a == b2) {
/* do this stuff, as well */
}
If you want to clearly delineate functionality for the different cases, use if-else or switch-case to make one test.
If you want different functionality for multiple cases, then use multiple if blocks as separate tests.
It's not a question of "best practices" so much as defining whether you have one test or multiple tests.
The are NOT functionally equivalent.
The only way it would be functionally equivalent is if you did an "if" statement for every single possible value of a (ie: every possibly int value, as defined in limits.h in C; using INT_MIN and INT_MAX, or equivalent in Java).
The else statement allows you to cover every possible remaining value without having to write millions of "if" statements.
Also, it's better coding practice to use if...else if...else, just like how in a switch/case statement, your compiler will nag you with a warning if you don't provide a "default" case statement. This prevents you from overlooking invalid values in your program. eg:
double square_root(double x) {
if(x > 0.0f) {
return sqrt(x);
} else if(x == 0.0f) {
return x;
} else {
printf("INVALID VALUE: x must be greater than zero");
return 0.0f;
}
}
Do you want to type millions of if statements for each possible value of x in this case? Doubt it :)
Cheers!
This totally depends on the condition you're testing. In your example it will make no difference eventually but as best practice, if you want ONE of the conditions to be eventually executed then you better use if else
if (x > 1) {
System.out.println("Hello!");
}else if (x < 1) {
System.out.println("Bye!");
}
Also note that if the first condition is TRUE the second will NOT be checked at all but if you use
if (x > 1) {
System.out.println("Hello!");
}
if (x < 1) {
System.out.println("Bye!");
}
The second condition will be checked even if the first condition is TRUE. This might be resolved by the optimizer eventually but as far as I know it behaves that way. Also the first one is the one is meant to be written and behaves like this so it is always the best choice for me unless the logic requires otherwise.
if and else if is different to two consecutive if statements. In the first, when the CPU takes the first if branch the else if won't be checked. In the two consecutive if statements, even if the the first if is checked and taken, the next if will also be check and take if the the condition is true.
I tend to think that using else if is easier more robust in the face of code changes. If someone were to adjust the control flow of the function and replaces a return with side-effect or a function call with a try-catch the else-if would fail hard if all conditions are truly exclusive. It really depends to much on the exact code you are working with to make a general judgment and you need to consider the possible trade-offs with brevity.
With return statements in each if branch.
In your code, you have return statements in each of the if conditions. When you have a situation like this, there are two ways to write this. The first is how you've written it in Example 1:
if (a == b1) {
return c1;
} else if (a == b2) {
return c2;
} else {
return c11;
}
The other is as follows:
if (a == b1) {
return c1;
}
if (a == b2) {
return c2;
}
return c11; // no if or else around this return statement
These two ways of writing your code are identical.
The way you wrote your code in example 2 wouldn't compile in C++ or Java (and would be undefined behavior in C), because the compiler doesn't know that you've covered all possible values of a so it thinks there's a code path through the function that can get you to the end of the function without returning a return value.
if (a == b1) {
return c1;
}
if (a == b2) {
return c2;
}
...
if (a == b11) {
return c11;
}
// what if you set a to some value c12?
Without return statements in each if branch.
Without return statements in each if branch, your code would be functionally identical only if the following statements are true:
You don't mutate the value of a in any of the if branches.
== is an equivalence relation (in the mathematical sense) and none of the b1 thru b11 are in the same equivalence class.
== doesn't have any side effects.
To clarify further about point #2 (and also point #3):
== is always an equivalence relation in C or Java and never has side effects.
In languages that let you override the == operator, such as C++, Ruby, or Scala, the overridden == operator may not be an equivalence relation, and it may have side effects. We certainly hope that whoever overrides the == operator was sane enough to write an equivalence relation that doesn't have side effects, but there's no guarantee.
In JavaScript and certain other programming languages with loose type conversion rules, there are cases built into the language where == is not transitive, or not symmetric. (In Javascript, === is an equivalence relation.)
In terms of performance, example #1 is guaranteed not to perform any comparisons after the one that matches. It may be possible for the compiler to optimize #2 to skip the extra comparisons, but it's unlikely. In the following example, it probably can't, and if the strings are long, the extra comparisons aren't cheap.
if (strcmp(str, "b1") == 0) {
...
}
if (strcmp(str, "b2") == 0) {
...
}
if (strcmp(str, "b3") == 0) {
...
}
I prefer if/else structures, because it's much easier to evaluate all possible states of your problem in every variation together with switches. It's more robust I find and quicker to debug especially when you do multiple Boolean evaluations in a weak-typed environment such as PHP, example why elseif is bad (exaggerated for demonstration):
if(a && (c == d))
{
} elseif ( b && (!d || a))
{
} elseif ( d == a && ( b^2 > c))
{
} else {
}
This problem has beyond 4^2=16 boolean states, which is simply to demonstrate the weak-typing effects that makes things even worse. It isn't so hard to imagine a three state variable, three variable problem involved in a if ab elseif bc type of way.
Leave optimization to the compiler.
In most cases, using if-elseif-else and switch statements over if-if-if statements is more efficient (since it makes it easier for the compiler to create jump/lookup tables) and better practice since it makes your code more readable, plus the compiler makes sure you include a default case in the switch. This answer, along with this table comparing the three different statements was synthesized using other answer posts on this page as well as those of a similar SO question.
I think these code snippets are equivalent for the simple reason that you have many return statements. If you had a single return statements, you would be using else constructs that here are unnecessary.
Your comparison relies on the fact that the body of the if statements return control from the method. Otherwise, the functionality would be different.
In this case, they perform the same functionality. The latter is much easier to read and understand in my opinion and would be my choice as which to use.
They potentially do different things.
If a is equal to b1 and b2, you enter two if blocks. In the first example, you only ever enter one. I imagine the first example is faster as the compiler probably does have to check each condition sequentially as certain comparison rules may apply to the object. It may be able to optimise them out... but if you only want one to be entered, the first approach is more obvious, less likely to lead to developer mistake or inefficient code, so I'd definitely recommend that.
CanSpice's answer is correct. An additional consideration for performance is to find out which conditional occurs most often. For example, if a==b1 only occurs 1% of the time, then you get better performance by checking the other case first.
Gir Loves Tacos answer is also good. Best practice is to ensure you have all cases covered.

Does an IF-Statement checks every OR operator?

At the moment I´m testing around with particles and have one important question.
if (condition a || condition b || condition c)
or
if(condition a)
if(condition b)
if(condition c){
}
Which is faster?
C++ uses what is known as short-circuit expression evaluation, which means that as soon as it encounters a term which determines the final result of the expression, (regardless of what the remaining terms may evaluate to,) it will stop evaluating terms.
Since TRUE OR X is TRUE regardless of the value of X, C++ will not bother evaluating X.
However, your cascaded if statement is not equivalent to the first expression. It is equivalent to an expression with multiple ANDs not multiple ORs.
This has likely been answered somewhere else before, but C++ uses the short circuit method, that is, if any condition passes, the rest are ignored (in the case of logical or: |).
The reverse is true for logical and: & - the first condition that fails short circuits the if statement and it exits early.
Here's an example:
if (condition a || condition b || condition c) {
// This code will execute if condition a is true, condition a or b is true, or if all three are true
}
if (condition a && condition b && condition c) {
// This code will only execute if all three are true, but if a is false, it will exit early, the same can be said for b
}

Is there any method or macro to simulate syntax "if(a <= b < c <= ...)" to replace "if(a<=b && b < c && c <= ...)"?

I want to find a method or macro which a <= b && b < c can rewrite as a <= b < c, because a <= b < c seems more straight forward and often seen in user requirement definition. Also a <= b && b < c needs to type b twice.
I searched about operators, but it seems (I think) only can add operation for custom class, but not alter the original operation. Also I know I can overload bool operator > but not sure I can add a new operation int operator > which returns the larger one. Also even operator overload works, a <= b < c will return c only, but not the true or false of statement a <= b < c (similar to MAX(c, MAX(b, a))).
Is there any method to simulate a <= b < c <= ...?
The comments already note it's a bad idea so I won't repeat that.
It's somewhat possible with macro's. None of those operators can be a macro name. But if you'd allow BADIDEA(a<=b<c), you can expand that as HelperClass()*a<=b<c. The idea is that Helperclass::operator* has the highest precendence. That means we parse it as HelperClass::operator*(HelperClass(), a).
This first part returns another HelperClass. HelperClass also overloads operator<= so we next get HelperClass::operator<=(firstExpr, b).
In this way, we can build a list of arguments passed to HelperClass It even supports BADIDEA(a<b<c<d). In the end, we just call HelperClass::operator bool which returns true if and only if the list of arguments is sorted.
ALternatively, you don't need to build the list of arguments, but can immediately evaluate them. HelperClass()*4<3 can already evaluate to false before you see <=7 in HelperClass()*4<3<=7

General method for constructing bitwise expressions satisfying constraints/with certain values?

Say I'm looking for a bitwise function to have certain values, for instance -
f(0b00,0b00)!=0
f(0b00,0b10)==0
f(0b10,0b10)!=0
f(0b11,0b10)!=0
f(0b01,0b10)==0
Is there a general method for constructing a single bitwise expression f for such systems? (I don't know for sure, but think there might be crappy solutions possible if you have gigantic expressions masking out one bit at a time, so let's say that the expressions have to work for all sizes of ints)
The best I've been able to do to convert the above is
f(int a, int b)
{
if (a==0 ) {
return b==0;
} else {
return (a&b)!=0;
}
}
I have a suspicion that it's difficult to combine (x==0) conditions with (x!=0) conditions (given x, is there a bitwise function f such that x==0 <=> f(x)!=0? ), but i don't know how much of an impediment that is here.
Any answers would be poured over with great interest :)
Peace,
S
The most general construction is an extended version of "minterms". Use bitwise operators to construct a predicate that is -1 iff the input matches a specific thing, AND the predicate with whatever you want the result to be, then OR all those things together. That leads to horrible expressions of course, possibly of exponential size.
Using arithmetic right shifts, you can construct a predicate p(x, c) = x == c:
p(x, c) = ~(((x ^ c) >> 31) | (-(x ^ c) >> 31))
Replace 31 by the size of an int minus one.
The only number such that it and its negation are both non-negative, is zero. So the thing inside the final complement is only zero if x ^ c == 0, which is the same as saying that x == c.
So in this example, you would have:
(p(a, 0x00) & p(b, 0x00)) |
(p(a, 0x10) & p(b, 0x10)) |
(p(a, 0x11) & p(b, 0x10))
Just expand it.. into something horrible.
Obviously this construction usually doesn't give you anything sensible. But it's general.
In the specific example, you could do:
f(a, b) = (p(a, 0) & p(b, 0)) | ~p(a & b, 0)
Which can be simplified a little again (obviously the xors go away if c == 0, and two complements balance each other out).